diff --git a/drawing/Common.lua b/drawing/Common.lua index 4e3d546..29c4aa7 100644 --- a/drawing/Common.lua +++ b/drawing/Common.lua @@ -282,6 +282,52 @@ M.annotated_scale_plot_set = function(asp, cr, value) ScaledTimeseries.update(asp.plot, cr, value) end +-------------------------------------------------------------------------------- +-- rate timecourse plots + +M.compute_derivative = function(x0, x1, update_frequency) + -- mask overflow + if x1 > x0 then + return (x1 - x0) * update_frequency + else + return 0 + end +end + +local build_differential = function(update_frequency) + return function(x0, x1) + -- mask overflow + if x1 > x0 then + return (x1 - x0) * update_frequency + else + return 0 + end + end +end + +M.build_rate_timeseries = function(x, y, w, h, format_fun, label_fun, spacing, + label, min_domain, update_freq, init) + return { + label = _left_text(F.make_point(x, y), label), + value = Text.build_formatted( + F.make_point(x + w, y), + 0, + M.right_text_style, + format_fun + ), + plot = M.initThemedScalePlot(x, y + spacing, w, h, label_fun, min_domain, update_freq), + prev_value = init, + derive = build_differential(update_freq), + } +end + +M.update_rate_timeseries = function(obj, cr, value) + local rate = obj.derive(obj.prev_value, value) + Text.set(obj.value, cr, rate) + ScaledTimeseries.update(obj.plot, cr, rate) + obj.prev_value = value +end + -------------------------------------------------------------------------------- -- arc (TODO this is just a dummy now to make everything organized diff --git a/drawing/Network.lua b/drawing/Network.lua index e0a8a05..3de7bdd 100644 --- a/drawing/Network.lua +++ b/drawing/Network.lua @@ -17,52 +17,6 @@ return function(update_freq) local INTERFACES = get_interfaces() - ----------------------------------------------------------------------------- - -- header - - local header = Common.Header( - Geometry.CENTER_RIGHT_X, - Geometry.TOP_Y, - Geometry.SECTION_WIDTH, - 'NETWORK' - ) - - ----------------------------------------------------------------------------- - -- download plot - - local value_format_function = function(bits) - local unit, value = Util.convert_data_val(bits) - return Util.precision_round_to_string(value, 3)..' '..unit..'b/s' - end - - local build_plot = function(y, label) - return Common.initLabeledScalePlot( - Geometry.CENTER_RIGHT_X, - y, - Geometry.SECTION_WIDTH, - PLOT_HEIGHT, - value_format_function, - Common.converted_y_label_format_generator('b'), - PLOT_SEC_BREAK, - label, - 2, - update_freq - ) - end - - local dnload = build_plot(header.bottom_y, 'Download') - - ----------------------------------------------------------------------------- - -- upload plot - - local upload = build_plot( - header.bottom_y + PLOT_HEIGHT + PLOT_SEC_BREAK * 2, - 'Upload' - ) - - ----------------------------------------------------------------------------- - -- update function - local INTERFACE_PATHS = {} for i = 1, #INTERFACES do local dir = string.format('/sys/class/net/%s/statistics/', INTERFACES[i]) @@ -87,46 +41,69 @@ return function(update_freq) return rx, tx end - local compute_speed = function(x0, x1) - -- mask overflow - if x1 > x0 then - return (x1 - x0) * update_freq - else - return 0 - end + local init_rx_bits, init_tx_bits = read_interfaces() + + local value_format_function = function(bits) + local unit, value = Util.convert_data_val(bits) + return Util.precision_round_to_string(value, 3)..' '..unit..'b/s' end - local prev_rx_bits, prev_tx_bits = read_interfaces() - - local update = function(cr) - local rx_bits, tx_bits = read_interfaces() - Common.annotated_scale_plot_set( - dnload, - cr, - compute_speed(prev_rx_bits, rx_bits) + local build_plot = function(y, label, init) + return Common.build_rate_timeseries( + Geometry.CENTER_RIGHT_X, + y, + Geometry.SECTION_WIDTH, + PLOT_HEIGHT, + value_format_function, + Common.converted_y_label_format_generator('b'), + PLOT_SEC_BREAK, + label, + 2, + update_freq, + init ) - Common.annotated_scale_plot_set( - upload, - cr, - compute_speed(prev_tx_bits, tx_bits) - ) - prev_rx_bits = rx_bits - prev_tx_bits = tx_bits end + ----------------------------------------------------------------------------- + -- header + + local header = Common.Header( + Geometry.CENTER_RIGHT_X, + Geometry.TOP_Y, + Geometry.SECTION_WIDTH, + 'NETWORK' + ) + + ----------------------------------------------------------------------------- + -- download plot + + local rx = build_plot(header.bottom_y, 'Download', init_rx_bits) + + ----------------------------------------------------------------------------- + -- upload plot + + local TX_Y = header.bottom_y + PLOT_HEIGHT + PLOT_SEC_BREAK * 2 + local tx = build_plot(TX_Y, 'Upload', init_tx_bits) + ----------------------------------------------------------------------------- -- main drawing functions + local update = function(cr) + local rx_bits, tx_bits = read_interfaces() + Common.update_rate_timeseries(rx, cr, rx_bits) + Common.update_rate_timeseries(tx, cr, tx_bits) + end + local draw_static = function(cr) Common.drawHeader(cr, header) - Common.annotated_scale_plot_draw_static(dnload, cr) - Common.annotated_scale_plot_draw_static(upload, cr) + Common.annotated_scale_plot_draw_static(rx, cr) + Common.annotated_scale_plot_draw_static(tx, cr) end local draw_dynamic = function(cr) update(cr) - Common.annotated_scale_plot_draw_dynamic(dnload, cr) - Common.annotated_scale_plot_draw_dynamic(upload, cr) + Common.annotated_scale_plot_draw_dynamic(rx, cr) + Common.annotated_scale_plot_draw_dynamic(tx, cr) end return {static = draw_static, dynamic = draw_dynamic} diff --git a/drawing/Power.lua b/drawing/Power.lua index 893771a..88c37b5 100644 --- a/drawing/Power.lua +++ b/drawing/Power.lua @@ -9,6 +9,61 @@ return function(update_freq) local PLOT_HEIGHT = 56 local PKG0_PATH = '/sys/class/powercap/intel-rapl:0/energy_uj' local DRAM_PATH = '/sys/class/powercap/intel-rapl:0:2/energy_uj' + local BAT_CURRENT_PATH = '/sys/class/power_supply/BAT0/current_now' + local BAT_VOLTAGE_PATH = '/sys/class/power_supply/BAT0/voltage_now' + + local read_milli = function(path) + return Util.read_file(path, nil, '*n') * 0.000001 + end + + local read_pkg0_joules = function() + return read_milli(PKG0_PATH) + end + + local read_dram_joules = function() + return read_milli(DRAM_PATH) + end + + local read_battery_current = function() + return read_milli(BAT_CURRENT_PATH) + end + + local read_battery_voltage = function() + return read_milli(BAT_VOLTAGE_PATH) + end + + local read_battery_power = function(is_using_ac) + if is_using_ac then + return 0 + else + return read_battery_current() * read_battery_voltage() + end + end + + local power_label_function = function(plot_max) + local fmt = Common.y_label_format_string(plot_max, 'W') + return function(watts) return string.format(fmt, watts) end + end + + local format_rapl = function(watts) + return Util.precision_round_to_string(watts, 3)..' W' + end + + local build_rate_plot = function(y, label, init) + return Common.build_rate_timeseries( + Geometry.RIGHT_X, + y, + Geometry.SECTION_WIDTH, + PLOT_HEIGHT, + format_rapl, + power_label_function, + PLOT_SEC_BREAK, + label, + 0, + update_freq, + init + ) + end ----------------------------------------------------------------------------- -- header @@ -23,114 +78,60 @@ return function(update_freq) ----------------------------------------------------------------------------- -- package 0 power plot - local power_label_function = function(plot_max) - local fmt = Common.y_label_format_string(plot_max, 'W') - return function(watts) return string.format(fmt, watts) end - end - - local power_format_function = function(watts) - return Util.precision_round_to_string(watts, 3)..' W' - end - - local build_plot = function(y, label, format_fun) - return Common.initLabeledScalePlot( - Geometry.RIGHT_X, - y, - Geometry.SECTION_WIDTH, - PLOT_HEIGHT, - format_fun, - power_label_function, - PLOT_SEC_BREAK, - label, - 0, - update_freq - ) - end - - local pkg0 = build_plot(header.bottom_y, 'PKG0', power_format_function) + local pkg0 = build_rate_plot(header.bottom_y, 'PKG0', read_pkg0_joules()) ----------------------------------------------------------------------------- -- DRAM power plot - local CORE_Y = header.bottom_y + TEXT_SPACING + PLOT_SEC_BREAK + PLOT_HEIGHT - - local dram = build_plot(CORE_Y, 'DRAM', power_format_function) + local DRAM_Y = header.bottom_y + TEXT_SPACING + PLOT_SEC_BREAK + PLOT_HEIGHT + local dram = build_rate_plot(DRAM_Y, 'DRAM', read_dram_joules()) ----------------------------------------------------------------------------- -- battery power plot - local ac_format_function = function(watts) + local format_ac = function(watts) if watts == 0 then return "A/C" else - return power_format_function(watts) + return format_rapl(watts) end end - local battery_draw = build_plot( - CORE_Y + PLOT_SEC_BREAK * 2 + PLOT_HEIGHT, + local BAT_Y = DRAM_Y + PLOT_SEC_BREAK * 2 + PLOT_HEIGHT + local bat = Common.initLabeledScalePlot( + Geometry.RIGHT_X, + BAT_Y, + Geometry.SECTION_WIDTH, + PLOT_HEIGHT, + format_ac, + power_label_function, + PLOT_SEC_BREAK, 'Battery Draw', - ac_format_function + 0, + update_freq ) ----------------------------------------------------------------------------- - -- update functions - - local read_uj = function(path) - return Util.read_file(path, nil, '*n') - end - - local prev_pkg0_uj_cnt = read_uj(PKG0_PATH) - local prev_dram_uj_cnt = read_uj(DRAM_PATH) - - local calculate_power = function(prev_cnt, cnt, update_frequency) - if cnt > prev_cnt then - return (cnt - prev_cnt) * update_frequency * 0.000001 - else - return 0 - end - end + -- main functions local update = function(cr, is_using_ac) - local pkg0_uj_cnt = read_uj(PKG0_PATH) - local dram_uj_cnt = read_uj(DRAM_PATH) - - local pkg0_power = calculate_power(prev_pkg0_uj_cnt, pkg0_uj_cnt, update_freq) - - Common.annotated_scale_plot_set(pkg0, cr, pkg0_power) - - local dram_power = calculate_power(prev_dram_uj_cnt, dram_uj_cnt, update_freq) - - Common.annotated_scale_plot_set(dram, cr, dram_power) - - prev_pkg0_uj_cnt = pkg0_uj_cnt - prev_dram_uj_cnt = dram_uj_cnt - - if is_using_ac then - Common.annotated_scale_plot_set(battery_draw, cr, 0) - else - local current = Util.read_file('/sys/class/power_supply/BAT0/current_now', nil, '*n') - local voltage = Util.read_file('/sys/class/power_supply/BAT0/voltage_now', nil, '*n') - local power = current * voltage * 0.000000000001 - Common.annotated_scale_plot_set(battery_draw, cr, power) - end + Common.update_rate_timeseries(pkg0, cr, read_pkg0_joules()) + Common.update_rate_timeseries(dram, cr, read_dram_joules()) + Common.annotated_scale_plot_set(bat, cr, read_battery_power(is_using_ac)) end - ----------------------------------------------------------------------------- - -- main functions - local draw_static = function(cr) Common.drawHeader(cr, header) Common.annotated_scale_plot_draw_static(pkg0, cr) Common.annotated_scale_plot_draw_static(dram, cr) - Common.annotated_scale_plot_draw_static(battery_draw, cr) + Common.annotated_scale_plot_draw_static(bat, cr) end local draw_dynamic = function(cr, is_using_ac) update(cr, is_using_ac) Common.annotated_scale_plot_draw_dynamic(pkg0, cr) Common.annotated_scale_plot_draw_dynamic(dram, cr) - Common.annotated_scale_plot_draw_dynamic(battery_draw, cr) + Common.annotated_scale_plot_draw_dynamic(bat, cr) end return {static = draw_static, dynamic = draw_dynamic} diff --git a/drawing/ReadWrite.lua b/drawing/ReadWrite.lua index 041c9f8..50d9309 100644 --- a/drawing/ReadWrite.lua +++ b/drawing/ReadWrite.lua @@ -16,62 +16,6 @@ return function(update_freq) local __tonumber = tonumber local __string_match = string.match - local __math_floor = math.floor - - ----------------------------------------------------------------------------- - -- header - - local header = Common.Header( - Geometry.CENTER_LEFT_X, - Geometry.TOP_Y, - Geometry.SECTION_WIDTH, - 'INPUT / OUTPUT' - ) - - ----------------------------------------------------------------------------- - -- reads - - -- local io_label_format_fun_generator = function(plot_max) - -- local new_unit, new_max = Util.convert_data_val(plot_max) - -- local conversion_factor = plot_max / new_max - -- local fmt = Common.y_label_format_string(new_max, new_unit..'B/s') - -- return function(bytes) - -- return string.format(fmt, bytes / conversion_factor) - -- end - -- end - - local format_value_function = function(bps) - local unit, value = Util.convert_data_val(bps) - return Util.precision_round_to_string(value, 3)..' '..unit..'B/s' - end - - local build_plot = function(y, label) - return Common.initLabeledScalePlot( - Geometry.CENTER_LEFT_X, - y, - Geometry.SECTION_WIDTH, - PLOT_HEIGHT, - format_value_function, - Common.converted_y_label_format_generator('B'), - PLOT_SEC_BREAK, - label, - 2, - update_freq - ) - end - - local reads = build_plot(header.bottom_y, 'Reads') - - ----------------------------------------------------------------------------- - -- writes - - local writes = build_plot( - header.bottom_y + PLOT_HEIGHT + PLOT_SEC_BREAK * 2, - 'Writes' - ) - - ----------------------------------------------------------------------------- - -- update function local DEVICE_PATHS = {} for i = 1, #DEVICES do @@ -89,36 +33,62 @@ return function(update_freq) return read_bytes * BLOCK_SIZE_BYTES, write_bytes * BLOCK_SIZE_BYTES end - local prev_read_bytes, prev_write_bytes = read_devices() + local init_read_bytes, init_write_bytes = read_devices() - local compute_rate = function(x0, x1) - -- mask overflow - if x1 > x0 then - return (x1 - x0) * update_freq - else - return 0 - end + local format_value_function = function(bps) + local unit, value = Util.convert_data_val(bps) + return Util.precision_round_to_string(value, 3)..' '..unit..'B/s' end - local update = function(cr) - local read_bytes, write_bytes = read_devices() - Common.annotated_scale_plot_set( - reads, - cr, - compute_rate(prev_read_bytes, read_bytes) + local build_plot = function(y, label, init) + return Common.build_rate_timeseries( + Geometry.CENTER_LEFT_X, + y, + Geometry.SECTION_WIDTH, + PLOT_HEIGHT, + format_value_function, + Common.converted_y_label_format_generator('B'), + PLOT_SEC_BREAK, + label, + 2, + update_freq, + init ) - Common.annotated_scale_plot_set( - writes, - cr, - compute_rate(prev_write_bytes, write_bytes) - ) - prev_read_bytes = read_bytes - prev_write_bytes = write_bytes end + ----------------------------------------------------------------------------- + -- header + + local header = Common.Header( + Geometry.CENTER_LEFT_X, + Geometry.TOP_Y, + Geometry.SECTION_WIDTH, + 'INPUT / OUTPUT' + ) + + ----------------------------------------------------------------------------- + -- reads + + local reads = build_plot(header.bottom_y, 'Reads', init_read_bytes) + + ----------------------------------------------------------------------------- + -- writes + + local writes = build_plot( + header.bottom_y + PLOT_HEIGHT + PLOT_SEC_BREAK * 2, + 'Writes', + init_write_bytes + ) + ----------------------------------------------------------------------------- -- main drawing functions + local update = function(cr) + local read_bytes, write_bytes = read_devices() + Common.update_rate_timeseries(reads, cr, read_bytes) + Common.update_rate_timeseries(writes, cr, write_bytes) + end + local draw_static = function(cr) Common.drawHeader(cr, header) Common.annotated_scale_plot_draw_static(reads, cr)