Feature: Task Killer - cockpit-project/cockpit GitHub Wiki

Relevant Links

Purpose

Provide a way to kill tasks in Cockpit, to test garbage collection and allow a person using Cockpit to manually free up resources on the client machine (the computer running the browser) as well as the server (in tasks that require heavy IO, etc.).

This feature is meant primarily as a debugging tool for developers of Cockpit and 3rd party add-ons. It may also be used by those who have a resource constrained computer or have managed several machines at once.

Audience

Developers

Provide a quick glance at resources used and have a method for killing off a part of Cockpit. This feature is mainly for manual garbage collection.

Users of Cockpit

Non-developers should not be using this in a normal situation. Killing off parts of Cockpit should not be necessary in normal usage.

As this will be a part of Cockpit (initially as a hidden feature in the near-future, accessed only as a shortcut key), all people who use Cockpit may still access the hidden task list to kill iframes, even if this feature isn't directly intended for them at this time.

Stories

Developer (primary audience)

Kara is working on a 3rd-party add-on for Cockpit. Whoops! She made a typo and now there's an infinite loop of canvas elements being added to her iframe, hammering her CPU.

She would love a way to kill the iframe her code is running on.

Admin (secondary audience)

John is a administrator. He uses his Cockpit session to manage several machines. When he disconnects from a machine, he still finds his browser to be sluggish. He wants to figure out why that is, and see if there is anything he can do about it.

Workflows

  1. Bring up the task killer (most likely with a key command that doesn't step on existing system, browser, or Cockpit hotkeys, such as Alt-Esc)
  2. Select task
  3. Kill task

Proposed implementation

After discussion, we have rescoped this feature to mainly target those who develop Cockpit. What would be easiest to interact with is a "global" hotkey (such as Alt+Esc or something similar) which would then bring up a simple task dialog, providing some minor details (as discussed below in resources) and a way to kill off tasks.

Mockup

active task killer mockup

  • Server names are left out if it is on the current server ("server2" is on another machine)
  • The currently visible frame is pre-selected
  • Additional items can be selected using the control key or clicking and dragging
  • Clicking on another item would select only that frame
  • Double-clicking an item closes the task and dismiss the dialog
  • Enter selects the default action of "End Task"
  • "Cancel" dismisses the dialog with no action
  • "End Task" closes the dialog
  • Closing the visible frame should provide a curtain screen with a reload button, similar to what the Docker page looks like when Docker is not running

Screenshot

Dominik and Garrett worked together on the CSS to made a few adjustments in the implementation. (The first pass doesn't have resources, so we removed the heading. We'll have to figure out a reliable way to show useful data.)

Active Pages screenshot

Future

For this first iteration, to fit within the short deadline, the design is complete.

The task list should probably be extended in the future in the following ways:

  • Make it discoverable from within the UI (most likely in the drop down menu or from the about box)
  • Touch friendliness should be enhanced (discoverability, multi-select, etc.)

As the current audience is developers of Cockpit (including 3rd party), we're adding it as a bonus feature for the time being.

Example HTML

Naturally, this needs modification. Ideally, it would be nice to have just the tbody scrollable, with affixed headers. Also, the inline CSS should move to classes (or current classes could be used if they apply)... and tr classes should be evaluated.

This is the HTML that was used for the mockup:

<div class="modal-content">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
      <span class="pficon pficon-close"></span>
    </button>
    <h4 class="modal-title" id="myModalLabel">Active Tasks</h4>
  </div>
  <div class="modal-body" style="
    overflow: auto;
    max-height: 75vh;
    padding: 0;
    ">
    <table class=" listing listing-ct" style="
      width: 100%;
      margin: 0;
      ">
      <thead>
        <tr>
          <th>Task Name</th>
          <th>Memory</th>
        </tr>
      </thead>
      <tbody>
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/system </td><td> 82 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/dashboard </td><td> 1 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/kubernetes </td><td> 2 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/kubernetes/registry </td><td> 22 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/storage </td><td> 1 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/docker </td><td> 5 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand active"><td> cockpit1:localhost/network </td><td> 222 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/machines </td><td> 82 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/system/services </td><td> 22 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/system/logs </td><td> 82 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/selinux/setroubleshoot </td><td> 82 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/subscriptions </td><td> 82 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/fleet-commander-admin </td><td> 19 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/playground/react-patterns </td><td> 22 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/system/terminal </td><td> 22 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/updates </td><td> 22 kb </td></tr> 
        <tr class="listing-ct-item listing-ct-nonavigate listing-ct-noexpand"><td> cockpit1:localhost/kdump </td><td> 82 kb </td></tr>  </tbody>
    </table>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
    <button type="button" class="btn btn-primary">End Task</button>
  </div>
</div>
</div>

Relevant art

GNOME

GNOME task list

Windows

Friendly(-ish) Details overload
Windows task list (friendly-ish) Windows task list (complex)

Mac

OS X task list

Resources

It would be nice to have some sort of stats for resource usage for each iframe. A lot of metrics we'd want to use are probably only available at a browser-level, instead of within the page. However, there should be some JS APIs we can use to display performance.

  • Navigation Timing / Performance API
    • Very broad browser support: http://caniuse.com/#feat=nav-timing
    • Docs: https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API
    • Quick overview: https://www.html5rocks.com/en/tutorials/webperformance/basics/
    • Using Navigation Timing on iframes: http://stackoverflow.com/questions/9944170/using-the-new-javascript-performance-timing-api-on-iframes
    • performance.getEntries() to get a list of various loaded resources and the stats (modify for iframe usage, of course)
    • Chrome has performance.memory (Firefox does not) — the about might need to be different between browsers, as it would be great to have actual memory values instead of approximates or (essentially) made-up resource measurements
    • Resource measurement I've figured out based on performance API, for render time (which should roughly indicate complexity of page) and resource usage (on load, not additional usage while manipulating the page):
      • Snippet showing the DOM render time for each iframe (run in dev console):

        $('iframe').each(function(i, iframe){ console.log(iframe.name,  iframe.contentWindow.performance.timing.domComplete - iframe.contentWindow.performance.timing.domLoading); })
      • Snippet to display the decoded (uncompressed in RAM) file sizes (which should be roughly equivalent with memory size) — note that this doesn't take into account actual RAM usage of the page in use, only the RAM used for resources (scripts, images, etc.):

        $('iframe').each(function(i, iframe){ console.log(iframe.name, iframe.contentWindow.performance.getEntries({entryType: "resource"}).reduce(function(prev, el){ return (prev.decodedBodySize || 0) + (el.decodedBodySize || 0) })); });
  • querySelector
    • document.querySelectorAll('*').length can be a very crude indicator on elements in the DOM; this could be used per iframe
    • it's generally not a great metric, as it doesn't count interactivity, memory usage, or other things (as it does take some elements longer to render than others)
⚠️ **GitHub.com Fallback** ⚠️