Author: eallen
Date: 2011-03-31 18:05:25 +0000 (Thu, 31 Mar 2011)
New Revision: 4676
Modified:
trunk/cumin/python/cumin/grid/slot.py
trunk/cumin/python/cumin/grid/slotvis.py
trunk/cumin/python/cumin/grid/slotvis.strings
trunk/cumin/python/cumin/inventory/system.py
trunk/cumin/resources/slots.swf
Log:
Artificial slot vis groups when the number of groups is > 50
Various white-space tweaks.
Modified: trunk/cumin/python/cumin/grid/slot.py
===================================================================
--- trunk/cumin/python/cumin/grid/slot.py 2011-03-30 18:42:39 UTC (rev 4675)
+++ trunk/cumin/python/cumin/grid/slot.py 2011-03-31 18:05:25 UTC (rev 4676)
@@ -129,7 +129,10 @@
max_width = 400
max_png_age = 30
- max_visible_slots = 200 # start drill-down mode after this number
+
+ # start creating artificial groupings after the number of real groups
+ max_top_level_items = 49
+
def __init__(self, app, name, param, desc):
super(SlotMapPage, self).__init__(app, name)
@@ -155,9 +158,8 @@
self.expanded.all = "all"
self.add_parameter(self.expanded)
- group = Parameter(app, "agroup")
- self.groups = ListParameter(app, "group", group)
- self.add_parameter(self.groups)
+ self.group = Parameter(app, "group")
+ self.add_parameter(self.group)
self.slots = SlotDataSet(app)
@@ -224,17 +226,69 @@
map.write(writer)
return writer.to_string()
+ def split_compound_attribute(self, record, attr):
+ if "|" in attr:
+ attr_list = attr.split("|")
+ atr_list = [record[x] for x in attr_list]
+ return ":".join(atr_list)
+ return ""
+
def get_info_array(self, records, array, attr):
+ '''
+ Creates a list of record indexes for each unique value of attr
+ @param records: all the records
+ @param array: list of indexes to check
+ @param attr: the rosemary attribute to create the array for
+ '''
d = dict()
for i in array:
- atr = records[i][attr]
+ try:
+ atr = records[i][attr]
+ except KeyError:
+ atr = self.split_compound_attribute(records[i], attr)
if not atr:
atr = "Unknown %s" % attr
if not atr in d:
- d[atr] = list()
- d[atr].append(i)
+ d[atr] = {"plist": list()}
+ d[atr]["klist"] = [atr]
+ d[atr]["plist"].append(i)
return d
+ def collapse_level(self, level_dict, count):
+ collapsed = dict()
+
+ def save_bucket(low_key, key, plist, keylist):
+ if low_key is not key:
+ coll_key = "%s - %s" % (low_key, key)
+ else:
+ coll_key = low_key
+ collapsed[coll_key] = {"plist": plist,
+ "klist": keylist}
+
+ plist = list()
+ keylist = list()
+ max_edge = len(level_dict) - 1
+ bucket_size = int(max_edge / count)
+ edge = bucket_size
+ low_key = None
+ for i, key in enumerate(sorted(level_dict.keys())):
+ if not low_key:
+ low_key = key
+ plist.extend(level_dict[key]["plist"])
+ keylist.append(key)
+ if i >= edge:
+ save_bucket(low_key, key, plist, keylist)
+ low_key = None
+ plist = list()
+ keylist = list()
+ edge += bucket_size
+ if edge > max_edge:
+ edge = max_edge
+
+ if low_key:
+ save_bucket(low_key, key, plist, keylist)
+ return collapsed
+
@classmethod
def get_cat_and_group(cls, state, activity):
act = activity
@@ -274,7 +328,7 @@
return "[]"
records = self.slots.sort_records(records)
- groups = self.groups.get(session)
+ group = self.group.get(session)
slot_count = len(records)
root = Element()
@@ -288,69 +342,96 @@
root.shape_info = self.shapes
root.activity_colors = self.interiors
expanded = self.expanded.get(session)
- leaves = True
- (root.tree, root.back) = self.treeify(records, range(slot_count), groups, 0,
- expanded, leaves, slot_count, json)
-
+ root.tree = self.treeify(records, range(slot_count), group, expanded)
+ root.back = False
return "[%s]" % root.create()
- def treeify(self, records, plist, groups, level, expanded, leaves, slot_count,
json):
+ def treeify(self, records, plist, group, expanded):
+ def add_branch(level_list, tree, back, group, key, slots):
+ if len(tree):
+ el = Element()
+ el.tree = tree
+ el.back = back
+ el.name = group
+ el.value = key
+ el.slots = slots
+ el.level = 0
+ level_list.append(el)
+
+ def gen_leaves(plist):
+ level_list = list()
+ for i in sorted(plist, key=lambda x:"%s%s%s" %
+ (records[x]["category_group"],
records[x]["category"], records[x]["Name"])):
+ el = Element()
+ el.job_id = records[i]["JobId"] and
records[i]["JobId"] or ""
+ el.activity = records[i]["Activity"] and
records[i]["Activity"] or "Unknown"
+ el.state = records[i]["State"] and
records[i]["State"] or "Unknown"
+ el.category = records[i]["category"]
+ el.category_group = records[i]["category_group"]
+ el.value = records[i]["Name"] and records[i]["Name"]
or ""
+ el.load_avg = records[i]["LoadAvg"] and
round(records[i]["LoadAvg"], 2) or 0
+ el.name = "slot"
+ el.slot_id = records[i]["_id"]
+ level_list.append(el)
+ return level_list
+
+ def gen_summary(plist):
+ # display summary info for all the slots under this grouping
+ level_list = list()
+ category_groups = self.get_cats(records, plist)
+ for category_group in sorted(category_groups):
+ el = Element()
+ el.name = "slot_info"
+ el.category = category_group
+ el.category_group = category_group
+ el.count = category_groups[category_group]["_count"]
+ try:
+ el.value = "%s.%s" % (records[plist[0]][group],
category_group) # uid
+ except KeyError:
+ atr = self.split_compound_attribute(records[plist[0]], group)
+ el.value = "%s.%s" % (atr, category_group)
+ level_list.append(el)
+ return level_list
+
level_list = list()
- # leaf
- if level == len(groups):
- if leaves:
- for i in sorted(plist, key=lambda x:"%s%s%s" %
- (records[x]["category_group"],
records[x]["category"], records[x]["Name"])):
- el = Element()
- el.job_id = records[i]["JobId"] and
records[i]["JobId"] or ""
- el.activity = records[i]["Activity"] and
records[i]["Activity"] or "Unknown"
- el.state = records[i]["State"] and
records[i]["State"] or "Unknown"
- el.category = records[i]["category"]
- el.category_group = records[i]["category_group"]
- el.value = records[i]["Name"] and
records[i]["Name"] or ""
- el.load_avg = records[i]["LoadAvg"] and
round(records[i]["LoadAvg"], 2) or 0
- el.name = "slot"
- el.slot_id = records[i]["_id"]
- level_list.append(el)
- return (level_list, True)
- else:
- if not expanded:
- # display summary info for all the slots under this grouping
- category_groups = self.get_cats(records, plist)
- for category_group in sorted(category_groups):
- el = Element()
- el.name = "slot_info"
- el.category = category_group
- el.category_group = category_group
- el.count = category_groups[category_group]["_count"]
- el.value = "%s.%s" %
(records[plist[0]][groups[level-1]], category_group) # uid
- level_list.append(el)
- return (level_list, False)
+ if not group:
+ tree = gen_leaves(plist)
+ add_branch(level_list, tree, False, "", "", len(plist))
+ return level_list
- # not a leaf
- group = groups[level]
- level_dict = self.get_info_array(records, plist, group)
+ original_level_dict = level_dict = self.get_info_array(records, plist, group)
+
+ if len(original_level_dict) > self.max_top_level_items:
+ # collapse groups into artificial sub-groups
+ level_dict = self.collapse_level(original_level_dict,
self.max_top_level_items)
+
for key in sorted(level_dict):
- el = Element()
- el.name = group
- el.value = key
- el.slots = len(level_dict[key])
- el.level = level
- if level < len(groups):
- if json == "slots":
- if expanded == key:
- leaves = True
- elif expanded == "None" and key is None:
- leaves = True
- else:
- leaves = False
- (el.tree, el.back) = self.treeify(records, level_dict[key], groups, level
+ 1,
- expanded, leaves, slot_count, json)
-
- if len(el.tree):
- level_list.append(el)
+ tree = list()
+ if not expanded:
+ if len(level_dict) == 1:
+ # there is only one grouping. no need to make them click on it
+ tree = gen_leaves(level_dict[key]["plist"])
+ add_branch(level_list, tree, False, group, key,
len(level_dict[key]["plist"]))
+ else:
+ # display the top level of groups (artificial or notural)
+ tree = gen_summary(level_dict[key]["plist"])
+ add_branch(level_list, tree, False, group, key,
len(level_dict[key]["plist"]))
+ elif expanded == key:
+ # lowest level of a natural group
+ if key in original_level_dict:
+ tree = gen_leaves(level_dict[key]["plist"])
+ add_branch(level_list, tree, True, group, key,
len(level_dict[key]["plist"]))
+ else:
+ # we want to display the groups that went into an atrificial
sub-group
+ for original_key in level_dict[key]["klist"]:
+ tree =
gen_summary(original_level_dict[original_key]["plist"])
+ add_branch(level_list, tree, True, group, original_key,
len(original_level_dict[original_key]["plist"]))
+ elif expanded in level_dict[key]["klist"]:
+ # lowest level of an artificial group
+ tree = gen_leaves(original_level_dict[expanded]["plist"])
+ add_branch(level_list, tree, True, group, expanded,
len(original_level_dict[expanded]["plist"]))
- return (level_list, False)
+ return level_list
class SlotMap(Widget):
def __init__(self, app, name):
Modified: trunk/cumin/python/cumin/grid/slotvis.py
===================================================================
--- trunk/cumin/python/cumin/grid/slotvis.py 2011-03-30 18:42:39 UTC (rev 4675)
+++ trunk/cumin/python/cumin/grid/slotvis.py 2011-03-31 18:05:25 UTC (rev 4676)
@@ -139,7 +139,7 @@
page.collector.set(sess, collector)
page.json.set(sess, "slots")
- page.groups.set(sess, [self.group_by.get(session)])
+ page.group.set(sess, self.group_by.get(session))
return sess.marshal()
@@ -188,6 +188,9 @@
self.add_state("System", "By system")
self.add_state("AccountingGroup", "By accounting group")
+ self.add_state("Activity|State", "By activity/state")
+ self.add_state("Arch", "By architecture")
+ self.add_state("OpSys", "By operating system")
#self.add_state("OpSys", "By opsys")
def get_click(self, session, state):
Modified: trunk/cumin/python/cumin/grid/slotvis.strings
===================================================================
--- trunk/cumin/python/cumin/grid/slotvis.strings 2011-03-30 18:42:39 UTC (rev 4675)
+++ trunk/cumin/python/cumin/grid/slotvis.strings 2011-03-31 18:05:25 UTC (rev 4676)
@@ -25,7 +25,6 @@
<div class="slot_visualization">
<div class="duration">{group_by}</div>
<div id="{id}_chart"></div>
- <div>Click and drag up and down within the list of slots to
scroll</div>
</div>
<div class="slot_legend">{slot_legend}</div><div
style="clear:both;"></div>
</div>
@@ -67,6 +66,8 @@
updatePoolSlotVis('{id}', "load");
}
}
+
+ // we want to drill down a level in the slot vis
function vis_expand(parent) {
if (parent == null) {
parent = "None";
@@ -74,20 +75,68 @@
var chart = cumin.getFlashChart("{id}");
var src = chart.src;
var branch = wooly.session.branch(src);
+
+ // save the value of the current expanded
+ var curExpand = "";
+ if (typeof branch.expanded != "undefined") {
+ curExpand = branch.expanded;
+ }
+
+ // expand to the level that was passed in
branch['expanded'] = parent;
+
+ // add the original expand to the end of the back list
+ var backList = [];
+ if (typeof branch.back != "undefined") {
+ backList = branch.back.split("|");
+ }
+ if (curExpand != "")
+ backList.push(curExpand);
+ if (backList.length > 0)
+ branch["back"] = backList.join("|");
+ else if (typeof branch.back != "undefined")
+ delete branch.back;
+
chart.src = branch.marshal();
updatePoolSlotVis("{id}", "load");
var myFx = new Fx.Scroll(window).toTop();
}
+
+ // we want to go back 1 level in the slot vis
function vis_back() {
var chart = cumin.getFlashChart("{id}");
var src = chart.src;
var branch = wooly.session.branch(src);
- if (typeof branch.expanded != "undefined")
- delete branch.expanded;
+
+ // get the current back list
+ var backList = [];
+ if (typeof branch.back != "undefined") {
+ backList = branch.back.split("|");
+ }
+
+ // remove the last entry from the back list
+ // and use it as the expand
+ var expand = backList.pop();
+ if (typeof expand != "undefined") {
+ branch["expanded"] = expand;
+ } else {
+ // we are back to the top level
+ if (typeof branch.expanded != "undefined")
+ delete branch.expanded;
+ }
+
+ // save the new back list
+ if (backList.length > 0) {
+ branch["back"] = backList.join("|");
+ } else {
+ if (typeof branch.back != "undefined")
+ delete branch.back;
+ }
+
chart.src = branch.marshal();
updatePoolSlotVis("{id}", "load");
}
+
function vis_treemap_over(type, value) {
var chart = cumin.getFlashChart("{id}");
if (chart) {
@@ -150,4 +199,9 @@
//]]>
</script>
-
\ No newline at end of file
+
+[SlotSelector.css]
+div.SlotSelector div.ObjectSelectorFilters {
+ padding-bottom: 0.5em;
+}
+
Modified: trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- trunk/cumin/python/cumin/inventory/system.py 2011-03-30 18:42:39 UTC (rev 4675)
+++ trunk/cumin/python/cumin/inventory/system.py 2011-03-31 18:05:25 UTC (rev 4676)
@@ -136,7 +136,7 @@
page.sysimage.set(sess, system)
page.json.set(sess, "slots")
- page.groups.set(sess, [])
+ page.group.set(sess, None)
return sess.marshal()
Modified: trunk/cumin/resources/slots.swf
===================================================================
(Binary files differ)