diff options
m--------- | Theron | 0 | ||||
-rw-r--r-- | benchmark/bm_registry.py | 95 | ||||
-rw-r--r-- | benchmark/run_benchmarks.py | 23 | ||||
-rw-r--r-- | benchmark/tb_combiner_array.py (renamed from benchmark/tb_many_1_to_1_blocks.py) | 0 | ||||
-rw-r--r-- | benchmark/tb_linear_chain.py | 27 | ||||
-rw-r--r-- | benchmark/tb_many_rate_changes.py | 4 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/block_actor.cpp | 4 | ||||
-rw-r--r-- | lib/gras_impl/block_actor.hpp | 2 | ||||
-rw-r--r-- | lib/gras_impl/stats.hpp | 4 | ||||
-rw-r--r-- | lib/theron_allocator.cpp | 100 | ||||
-rw-r--r-- | lib/top_block_query.cpp | 10 | ||||
-rw-r--r-- | python/gras/query/CMakeLists.txt | 1 | ||||
-rw-r--r-- | python/gras/query/chart_allocator_counts.js | 46 | ||||
-rw-r--r-- | python/gras/query/chart_factory.js | 1 | ||||
-rw-r--r-- | python/gras/query/main.html | 1 |
16 files changed, 182 insertions, 139 deletions
diff --git a/Theron b/Theron -Subproject e31d0a51e9ea245e7a981365fb58023d24e8649 +Subproject 1a87688a68c58305947ec2d3eb83e51d8724655 diff --git a/benchmark/bm_registry.py b/benchmark/bm_registry.py index 7c9bb1c..da7efe4 100644 --- a/benchmark/bm_registry.py +++ b/benchmark/bm_registry.py @@ -6,7 +6,7 @@ def tokwargs(**kwargs): return kwargs INSTALL_PREFIX = '/opt/usr' -DURATION = '1.7' #seconds +DURATION = '1.3' #seconds GRAS_ENV = { 'PATH': os.path.join(INSTALL_PREFIX, 'gras/bin:$PATH:%s'%os.getenv('PATH')), @@ -20,15 +20,27 @@ GR_ENV = { 'PYTHONPATH': os.path.join(INSTALL_PREFIX, 'gr/lib/python2.7/dist-packages:%s'%os.getenv('PYTHONPATH')), } -BENCHMARK_MANY_11_BLOCKS = tokwargs( - wat='Benchmark the schedulers with many 1:1 ratio blocks', +BENCHMARK_LINEAR_CHAIN = tokwargs( + wat='Benchmark the schedulers with linear chain topology', moar='''\ -- Compare simultaneous 1:1 ratio blocks in each scheduler. +- Topology is a linear chain of one input/one output blocks. - GRAS will use only the buffer pool allocator, and every work will fully consume available buffers.''', tests = [ - tokwargs(wat='GRAS', args=['tb_many_1_to_1_blocks.py', DURATION], env=GRAS_ENV), - tokwargs(wat='GR', args=['tb_many_1_to_1_blocks.py', DURATION], env=GR_ENV), + tokwargs(wat='GRAS', args=['tb_linear_chain.py', DURATION], env=GRAS_ENV, expand=True), + tokwargs(wat='GRSS', args=['tb_linear_chain.py', DURATION], env=GR_ENV), + ], +) + +BENCHMARK_COMBINER_ARRAY = tokwargs( + wat='Benchmark the schedulers with combiner array topology', + moar='''\ +- Topology is a tower of two input math blocks. +- GRAS will use only the buffer pool allocator, +and every work will fully consume available buffers.''', + tests = [ + tokwargs(wat='GRAS', args=['tb_combiner_array.py', DURATION], env=GRAS_ENV, expand=True), + tokwargs(wat='GRSS', args=['tb_combiner_array.py', DURATION], env=GR_ENV), ], ) @@ -39,40 +51,58 @@ BENCHMARK_MANY_RATE_BLOCKS = tokwargs( - GRAS will use only the buffer pool allocator, and every work will fully consume available buffers.''', tests = [ - tokwargs(wat='GRAS', args=['tb_many_rate_changes.py', '--dur', DURATION], env=GRAS_ENV), - tokwargs(wat='GR', args=['tb_many_rate_changes.py', '--dur', DURATION], env=GR_ENV), + tokwargs(wat='GRAS', args=['tb_many_rate_changes.py', '--dur', DURATION], env=GRAS_ENV, expand=True), + tokwargs(wat='GRSS', args=['tb_many_rate_changes.py', '--dur', DURATION], env=GR_ENV), + ], +) + +BENCHMARK_DFIR_BLOCK = tokwargs( + wat='Benchmark the schedulers with a FIR block', + moar='''\ +- Compare filter blocks in each scheduler. +- Shows both schedulers using circular buffer.''', + tests = [ + tokwargs(wat='GRAS', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'dfir'], env=GRAS_ENV, expand=True), + tokwargs(wat='GRSS', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'dfir'], env=GR_ENV), ], ) -BENCHMARK_FILTER_BLOCK = tokwargs( - wat='Benchmark the schedulers with a filter block', +BENCHMARK_RESAMP_BLOCK = tokwargs( + wat='Benchmark the schedulers with a resampler block', moar='''\ - Compare filter blocks in each scheduler. -- Shows both schedulers using circular buffer. -- The decimating FIR filter is compared. -- The rational resampler filter is compared.''', +- Shows both schedulers using circular buffer.''', + tests = [ + tokwargs(wat='GRAS', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'resamp'], env=GRAS_ENV, expand=True), + tokwargs(wat='GRSS', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'resamp'], env=GR_ENV), + ], +) + +BENCHMARK_ADD_OPS = tokwargs( + wat='Benchmark GrExtras vs gr-blocks adder blocks', + moar='''\ +- Compare math block implementations using GRAS. +- All blocks are using vector optimization. +- GrExtras math blocks avoid an unnecessary memcpy. +- GrExtras math blocks enable automatic bufer in-placing.''', tests = [ - tokwargs(wat='GRAS decim FIR', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'dfir'], env=GRAS_ENV), - tokwargs(wat='GR decim FIR', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'dfir'], env=GR_ENV), - tokwargs(wat='GRAS resampler', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'resamp'], env=GRAS_ENV), - tokwargs(wat='GR resampler', args=['tb_filter_block.py', '--dur', DURATION, '--which', 'resamp'], env=GR_ENV), + tokwargs(wat='GrExtras\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'extras_add'], env=GRAS_ENV, expand=True), + tokwargs(wat='gr-blocks\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'blocks_add'], env=GRAS_ENV, expand=True), + tokwargs(wat='gr-blocks\n(GRSS)', args=['tb_grextras_math.py', DURATION, 'blocks_add'], env=GR_ENV), ], ) -BENCHMARK_MATH_OPS = tokwargs( - wat='Benchmark GrExtras vs gr-blocks math blocks', +BENCHMARK_MULT_OPS = tokwargs( + wat='Benchmark GrExtras vs gr-blocks multiplier blocks', moar='''\ - Compare math block implementations using GRAS. - All blocks are using vector optimization. - GrExtras math blocks avoid an unnecessary memcpy. - GrExtras math blocks enable automatic bufer in-placing.''', tests = [ - tokwargs(wat='GrExtras Add\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'extras_add'], env=GRAS_ENV), - tokwargs(wat='gr-blocks Add\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'blocks_add'], env=GRAS_ENV), - tokwargs(wat='gr-blocks Add\n(GR)', args=['tb_grextras_math.py', DURATION, 'blocks_add'], env=GR_ENV), - tokwargs(wat='GrExtras Mult\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'extras_mult'], env=GRAS_ENV), - tokwargs(wat='gr-blocks Mult\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'blocks_mult'], env=GRAS_ENV), - tokwargs(wat='gr-blocks Mult\n(GR)', args=['tb_grextras_math.py', DURATION, 'blocks_mult'], env=GR_ENV), + tokwargs(wat='GrExtras\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'extras_mult'], env=GRAS_ENV, expand=True), + tokwargs(wat='gr-blocks\n(GRAS)', args=['tb_grextras_math.py', DURATION, 'blocks_mult'], env=GRAS_ENV, expand=True), + tokwargs(wat='gr-blocks\n(GRSS)', args=['tb_grextras_math.py', DURATION, 'blocks_mult'], env=GR_ENV), ], ) @@ -82,16 +112,19 @@ BENCHMARK_DELAY_BLOCKS = tokwargs( - Compare delay block implementations using GRAS. - The GrExtras implementation uses zero-copy.''', tests = [ - tokwargs(wat='GrExtras Delay\n(GRAS)', args=['tb_grextras_delay.py', DURATION, 'extras_delay'], env=GRAS_ENV), - tokwargs(wat='gr-core Delay\n(GRAS)', args=['tb_grextras_delay.py', DURATION, 'core_delay'], env=GRAS_ENV), - tokwargs(wat='gr-core Delay\n(GR)', args=['tb_grextras_delay.py', DURATION, 'core_delay'], env=GR_ENV), + tokwargs(wat='GrExtras\n(GRAS)', args=['tb_grextras_delay.py', DURATION, 'extras_delay'], env=GRAS_ENV, expand=True), + tokwargs(wat='gr-core\n(GRAS)', args=['tb_grextras_delay.py', DURATION, 'core_delay'], env=GRAS_ENV, expand=True), + tokwargs(wat='gr-core\n(GRSS)', args=['tb_grextras_delay.py', DURATION, 'core_delay'], env=GR_ENV), ], ) BENCHMARKS = ( - BENCHMARK_MANY_11_BLOCKS, + BENCHMARK_LINEAR_CHAIN, + BENCHMARK_COMBINER_ARRAY, BENCHMARK_MANY_RATE_BLOCKS, - BENCHMARK_FILTER_BLOCK, - BENCHMARK_MATH_OPS, + BENCHMARK_DFIR_BLOCK, + BENCHMARK_RESAMP_BLOCK, + BENCHMARK_ADD_OPS, + BENCHMARK_MULT_OPS, BENCHMARK_DELAY_BLOCKS, ) diff --git a/benchmark/run_benchmarks.py b/benchmark/run_benchmarks.py index 8cb3503..779aa6a 100644 --- a/benchmark/run_benchmarks.py +++ b/benchmark/run_benchmarks.py @@ -15,7 +15,7 @@ cpu_count = multiprocessing.cpu_count() from bm_registry import BENCHMARKS -NUM_RUNS_PER_TEST = 5 +NUM_RUNS_PER_TEST = 3 BAD_BOOST_KILL_DURATION = 5.0 #seconds @@ -45,6 +45,25 @@ def run_a_single_one(args, env): raise Exception, 'no result found!' #return t1-t0 +def expand_tests(bm): + for run in bm['tests']: + if run.has_key('expand') and run['expand']: + import copy + new_run = copy.deepcopy(run) + new_run['wat'] += '\n(Block)' + new_run['env']['GRAS_YIELD'] = 'BLOCKING' + yield new_run + new_run = copy.deepcopy(run) + new_run['wat'] += '\n(Spin)' + new_run['env']['GRAS_YIELD'] = 'STRONG' + yield new_run + new_run = copy.deepcopy(run) + new_run['wat'] += '\n(TPB)' + new_run['env']['GRAS_YIELD'] = 'BLOCKING' + new_run['env']['GRAS_TPP'] = '1' + yield new_run + else: yield run + def do_a_benchmark(bm): title = bm['wat'] print '#'*(len(title)+25) @@ -53,7 +72,7 @@ def do_a_benchmark(bm): result_means = list() result_stddevs = list() test_names = list() - for run in bm['tests']: + for run in expand_tests(bm): test_name = run['wat'] print '-'*(len(test_name)+25) print '-- running test:', test_name.replace('\n', ' ') diff --git a/benchmark/tb_many_1_to_1_blocks.py b/benchmark/tb_combiner_array.py index c545d7e..c545d7e 100644 --- a/benchmark/tb_many_1_to_1_blocks.py +++ b/benchmark/tb_combiner_array.py diff --git a/benchmark/tb_linear_chain.py b/benchmark/tb_linear_chain.py new file mode 100644 index 0000000..184b6e1 --- /dev/null +++ b/benchmark/tb_linear_chain.py @@ -0,0 +1,27 @@ +import gnuradio +from gnuradio import gr +from gnuradio import blocks as grblocks +import sys + +if __name__ == '__main__': + + duration = float(sys.argv[1]) + + tb = gr.top_block() + src = gr.null_source(8) + b0 = gr.copy(8) + b1 = grblocks.sub_cc() + b2 = gr.copy(8) + b3 = grblocks.divide_cc() + b4 = gr.copy(8) + sink = gr.null_sink(8) + + tb.connect(src, b0, b1, b2, b3, b4, sink) + + import time + tb.start() + time.sleep(duration) + print '##RESULT##', sink.nitems_read(0)/duration + import sys; sys.stdout.flush() + tb.stop() + tb.wait() diff --git a/benchmark/tb_many_rate_changes.py b/benchmark/tb_many_rate_changes.py index e94179f..2930dd6 100644 --- a/benchmark/tb_many_rate_changes.py +++ b/benchmark/tb_many_rate_changes.py @@ -30,15 +30,13 @@ class many_rate_changing(gr.top_block): self.gr_unpacked_to_packed_xx_0 = gr.unpacked_to_packed_bb(2, gr.GR_LSB_FIRST) self.gr_packed_to_unpacked_xx_0 = gr.packed_to_unpacked_bb(2, gr.GR_MSB_FIRST) self.gr_null_sink_0_2 = gr.null_sink(gr.sizeof_char*1) - self.blocks_keep_m_in_n_0 = blocks.keep_m_in_n(gr.sizeof_float, 3, 20, 0) self.blocks_float_to_char_0 = blocks.float_to_char(1, 1) self.blocks_char_to_float_0 = blocks.char_to_float(1, 1) ################################################## # Connections ################################################## - self.connect((self.blocks_char_to_float_0, 0), (self.blocks_keep_m_in_n_0, 0)) - self.connect((self.blocks_keep_m_in_n_0, 0), (self.blocks_float_to_char_0, 0)) + self.connect((self.blocks_char_to_float_0, 0), (self.blocks_float_to_char_0, 0)) self.connect((self.blocks_float_to_char_0, 0), (self.gr_packed_to_unpacked_xx_0, 0)) self.connect((self.gr_unpacked_to_packed_xx_0, 0), (self.blocks_char_to_float_0, 0)) self.connect((self.random_source_x_0, 0), (self.gr_unpacked_to_packed_xx_0, 0)) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ba7e76e..bb74dc9 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -24,6 +24,8 @@ add_definitions(${THERON_DEFINES}) list(APPEND GRAS_LIBRARIES ${THERON_LIBRARIES}) list(APPEND GRAS_SOURCES ${THERON_SOURCES}) +add_definitions(-DTHERON_ENABLE_DEFAULTALLOCATOR_CHECKS=1) + ######################################################################## # Setup Apology Deps ######################################################################## @@ -62,7 +64,6 @@ list(APPEND GRAS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/top_block.cpp ${CMAKE_CURRENT_SOURCE_DIR}/top_block_query.cpp ${CMAKE_CURRENT_SOURCE_DIR}/register_messages.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/theron_allocator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/weak_container.cpp ) diff --git a/lib/block_actor.cpp b/lib/block_actor.cpp index 750e52d..fe7f79e 100644 --- a/lib/block_actor.cpp +++ b/lib/block_actor.cpp @@ -14,7 +14,7 @@ ThreadPoolConfig::ThreadPoolConfig(void) thread_count = std::max(size_t(2), thread_count); node_mask = 0; processor_mask = 0xffffffff; - yield_strategy = "STRONG"; + yield_strategy = "BLOCKING"; //environment variable override const char * gras_yield = getenv("GRAS_YIELD"); @@ -44,7 +44,7 @@ ThreadPool::ThreadPool(const ThreadPoolConfig &config) ); if (config.yield_strategy.empty()) params.mYieldStrategy = Theron::YIELD_STRATEGY_STRONG; - //else if (config.yield_strategy == "BLOCKING") params.mYieldStrategy = Theron::YIELD_STRATEGY_BLOCKING; + else if (config.yield_strategy == "BLOCKING") params.mYieldStrategy = Theron::YIELD_STRATEGY_BLOCKING; else if (config.yield_strategy == "POLITE") params.mYieldStrategy = Theron::YIELD_STRATEGY_POLITE; else if (config.yield_strategy == "STRONG") params.mYieldStrategy = Theron::YIELD_STRATEGY_STRONG; else if (config.yield_strategy == "AGGRESSIVE") params.mYieldStrategy = Theron::YIELD_STRATEGY_AGGRESSIVE; diff --git a/lib/gras_impl/block_actor.hpp b/lib/gras_impl/block_actor.hpp index 5444bb0..502f974 100644 --- a/lib/gras_impl/block_actor.hpp +++ b/lib/gras_impl/block_actor.hpp @@ -129,6 +129,8 @@ struct BlockActor : Apology::Worker OutputBufferQueues output_queues; std::vector<bool> produce_outputs; BitSet inputs_available; + std::vector<time_ticks_t> time_input_not_ready; + std::vector<time_ticks_t> time_output_not_ready; //tag and msg tracking std::vector<bool> input_tags_changed; diff --git a/lib/gras_impl/stats.hpp b/lib/gras_impl/stats.hpp index 7edab29..d9e2341 100644 --- a/lib/gras_impl/stats.hpp +++ b/lib/gras_impl/stats.hpp @@ -37,6 +37,10 @@ struct BlockStats std::vector<item_index_t> tags_produced; std::vector<item_index_t> msgs_produced; + //port starvation tracking + std::vector<time_ticks_t> inputs_idle; + std::vector<time_ticks_t> outputs_idle; + //instantaneous port status std::vector<size_t> items_enqueued; std::vector<size_t> msgs_enqueued; diff --git a/lib/theron_allocator.cpp b/lib/theron_allocator.cpp deleted file mode 100644 index 9db9367..0000000 --- a/lib/theron_allocator.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. - -/*********************************************************************** - * There is allocation overhead for sending messages. - * Want per worker-allocator for message allocation... - * But until thats possible, install a new global allocator. - * This allocator uses a fixed pool for small sized buffers, - * and otherwise the regular malloc/free for larger buffers. - **********************************************************************/ - -#include <gras/gras.hpp> -#include <gras_impl/debug.hpp> -#include <Theron/Detail/Threading/SpinLock.h> -#include <Theron/IAllocator.h> -#include <Theron/AllocatorManager.h> -#include <boost/circular_buffer.hpp> - -#define MY_ALLOCATOR_CHUNK_SIZE 256 -#define MY_ALLOCATOR_POOL_SIZE (MY_ALLOCATOR_CHUNK_SIZE * (1 << 18)) - -static unsigned long long unwanted_malloc_count = 0; - -static struct ExitPrinter -{ - ExitPrinter(void){} - ~ExitPrinter(void) - { - if (unwanted_malloc_count) - { - VAR(unwanted_malloc_count); - } - } -} exit_printer; - -static struct WorkerAllocator : Theron::IAllocator -{ - WorkerAllocator(void) - { - const size_t N = MY_ALLOCATOR_POOL_SIZE/MY_ALLOCATOR_CHUNK_SIZE; - queue.set_capacity(N); - for (size_t i = 0; i < N; i++) - { - const ptrdiff_t pool_ptr = ptrdiff_t(pool) + i*MY_ALLOCATOR_CHUNK_SIZE; - queue.push_back((void *)pool_ptr); - } - pool_end = ptrdiff_t(pool) + MY_ALLOCATOR_POOL_SIZE; - Theron::AllocatorManager::Instance().SetAllocator(this); - } - - ~WorkerAllocator(void) - { - //NOP - } - - void *Allocate(const SizeType size) - { - if GRAS_LIKELY(size <= MY_ALLOCATOR_CHUNK_SIZE) - { - mSpinLock.Lock(); - if GRAS_UNLIKELY(queue.empty()) - { - unwanted_malloc_count++; - mSpinLock.Unlock(); - return std::malloc(size); - } - void *memory = queue.front(); - queue.pop_front(); - mSpinLock.Unlock(); - return memory; - } - else - { - //std::cout << "malloc size " << size << std::endl; - return std::malloc(size); - } - } - - void Free(void *const memory) - { - const bool in_pool = ptrdiff_t(memory) >= ptrdiff_t(pool) and ptrdiff_t(memory) < pool_end; - if GRAS_LIKELY(in_pool) - { - mSpinLock.Lock(); - queue.push_front(memory); - mSpinLock.Unlock(); - } - else - { - std::free(memory); - } - } - - boost::circular_buffer<void *> queue; - THERON_PREALIGN(GRAS_MAX_ALIGNMENT) - char pool[MY_ALLOCATOR_POOL_SIZE] - THERON_POSTALIGN(GRAS_MAX_ALIGNMENT); - ptrdiff_t pool_end; - Theron::Detail::SpinLock mSpinLock; - -} my_alloc; diff --git a/lib/top_block_query.cpp b/lib/top_block_query.cpp index b000a2d..3203507 100644 --- a/lib/top_block_query.cpp +++ b/lib/top_block_query.cpp @@ -7,6 +7,7 @@ #include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/xml_parser.hpp> #include <boost/regex.hpp> +#include <Theron/DefaultAllocator.h> #include <algorithm> #include <sstream> @@ -87,6 +88,15 @@ static std::string query_stats(ElementImpl *self, const boost::property_tree::pt root.put("now", time_now()); root.put("tps", time_tps()); + //allocator debugs + Theron::DefaultAllocator *allocator = dynamic_cast<Theron::DefaultAllocator *>(Theron::AllocatorManager::Instance().GetAllocator()); + if (allocator) + { + root.put("bytes_allocated", allocator->GetBytesAllocated()); + root.put("peak_bytes_allocated", allocator->GetPeakBytesAllocated()); + root.put("allocation_count", allocator->GetAllocationCount()); + } + //iterate through blocks boost::property_tree::ptree blocks; BOOST_FOREACH(const GetStatsMessage &message, receiver.messages) diff --git a/python/gras/query/CMakeLists.txt b/python/gras/query/CMakeLists.txt index ab49532..a448068 100644 --- a/python/gras/query/CMakeLists.txt +++ b/python/gras/query/CMakeLists.txt @@ -20,6 +20,7 @@ INSTALL( chart_overall_throughput.js chart_handler_breakdown.js chart_total_io_counts.js + chart_allocator_counts.js main.css DESTINATION ${GR_PYTHON_DIR}/gras/query COMPONENT ${GRAS_COMP_PYTHON} diff --git a/python/gras/query/chart_allocator_counts.js b/python/gras/query/chart_allocator_counts.js new file mode 100644 index 0000000..cc06d24 --- /dev/null +++ b/python/gras/query/chart_allocator_counts.js @@ -0,0 +1,46 @@ +function GrasChartAllocatorCounts(args, panel) +{ + //input checking + if (args.block_ids.length != 0) throw gras_error_dialog( + "GrasChartAllocatorCounts", + "Error making allocator counts chart.\n"+ + "Do not specify any blocks for this chart." + ); + + //settings + this.div = $('<div />').attr({class:'chart_total_io_counts'}); + $(panel).append(this.div); + this.title = "Theron allocator counts" +} + +GrasChartAllocatorCounts.prototype.update = function(point) +{ + var ul = $('<ul />'); + $('ul', this.div).remove(); //clear old lists + this.div.append(ul); + + function make_entry(strong, span) + { + var li = $('<li />'); + var strong = $('<strong />').text(strong + ": "); + var span = $('<span />').text(span); + li.append(strong); + li.append(span); + ul.append(li); + } + + var stuff = [ + ['Allocated', 'bytes', 'bytes_allocated'], + ['Peak size', 'bytes', 'peak_bytes_allocated'], + ['Malloc\'d', 'times', 'allocation_count'], + ]; + + $.each(stuff, function(contents_i, contents) + { + var dir = contents[0]; + var units = contents[1]; + var key = contents[2]; + var count = (key in point)? point[key] : 0; + if (count > 0) make_entry(dir, count.toString() + ' ' + units); + }); +} diff --git a/python/gras/query/chart_factory.js b/python/gras/query/chart_factory.js index 122d222..dbb141a 100644 --- a/python/gras/query/chart_factory.js +++ b/python/gras/query/chart_factory.js @@ -13,6 +13,7 @@ var gras_chart_get_registry = function() {key:'overall_throughput', name:'Overall Throughput', factory:GrasChartOverallThroughput}, {key:'handler_breakdown', name:'Handler Breakdown', factory:GrasChartHandlerBreakdown}, {key:'total_io_counts', name:'I/O port Totals', factory:GrasChartTotalIoCounts}, + {key:'allocator_counts', name:'Allocator Counts', factory:GrasChartAllocatorCounts}, ]; } diff --git a/python/gras/query/main.html b/python/gras/query/main.html index b64d53f..64d5809 100644 --- a/python/gras/query/main.html +++ b/python/gras/query/main.html @@ -15,6 +15,7 @@ <script type="text/javascript" src="/chart_overall_throughput.js"></script> <script type="text/javascript" src="/chart_handler_breakdown.js"></script> <script type="text/javascript" src="/chart_total_io_counts.js"></script> + <script type="text/javascript" src="/chart_allocator_counts.js"></script> <script type="text/javascript" src="/main.js"></script> <script type="text/javascript"> google.load('visualization', '1.0', {'packages':['corechart']}); |