From 4bc311cf927208842650eacaed69eeacdd57f6df Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 00:24:42 +0200 Subject: [PATCH 1/9] xray: import Xray profiler from Chromium Native Client --- hermit/usr/xray/LICENSE | 28 ++ hermit/usr/xray/browser.c | 163 +++++++ hermit/usr/xray/demangle.c | 25 ++ hermit/usr/xray/hashtable.c | 205 +++++++++ hermit/usr/xray/parsesymbols.c | 96 ++++ hermit/usr/xray/report.c | 209 +++++++++ hermit/usr/xray/stringpool.c | 94 ++++ hermit/usr/xray/symtable.c | 200 +++++++++ hermit/usr/xray/xray.c | 780 +++++++++++++++++++++++++++++++++ hermit/usr/xray/xray.h | 117 +++++ hermit/usr/xray/xray.odt | Bin 0 -> 52528 bytes hermit/usr/xray/xray_priv.h | 207 +++++++++ 12 files changed, 2124 insertions(+) create mode 100644 hermit/usr/xray/LICENSE create mode 100644 hermit/usr/xray/browser.c create mode 100644 hermit/usr/xray/demangle.c create mode 100644 hermit/usr/xray/hashtable.c create mode 100644 hermit/usr/xray/parsesymbols.c create mode 100644 hermit/usr/xray/report.c create mode 100644 hermit/usr/xray/stringpool.c create mode 100644 hermit/usr/xray/symtable.c create mode 100644 hermit/usr/xray/xray.c create mode 100644 hermit/usr/xray/xray.h create mode 100644 hermit/usr/xray/xray.odt create mode 100644 hermit/usr/xray/xray_priv.h diff --git a/hermit/usr/xray/LICENSE b/hermit/usr/xray/LICENSE new file mode 100644 index 000000000..29b40573f --- /dev/null +++ b/hermit/usr/xray/LICENSE @@ -0,0 +1,28 @@ +Copyright 2011, The Chromium Authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/hermit/usr/xray/browser.c b/hermit/usr/xray/browser.c new file mode 100644 index 000000000..a150c5a3f --- /dev/null +++ b/hermit/usr/xray/browser.c @@ -0,0 +1,163 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +/* XRay -- a simple profiler for Native Client */ + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ppapi/c/dev/ppb_trace_event_dev.h" +#include "xray/xray_priv.h" + + +#if defined(XRAY) +static PPB_Trace_Event_Dev* ppb_trace_event_interface = NULL; + +static const char* XRayGetName(struct XRaySymbolTable* symbols, + struct XRayTraceBufferEntry* e) { + uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr); + struct XRaySymbol* symbol = XRaySymbolTableLookup(symbols, addr); + return XRaySymbolGetName(symbol); +} + +struct XRayTimestampPair XRayGenerateTimestampsNow(void) { + struct XRayTimestampPair pair; + assert(ppb_trace_event_interface); + + XRayGetTSC(&pair.xray); + pair.pepper = ppb_trace_event_interface->Now(); + return pair; +} + +/* see chromium/src/base/trace_event/trace_event.h */ +#define TRACE_VALUE_TYPE_UINT (2) +#define TRACE_VALUE_TYPE_DOUBLE (4) +#define TRACE_VALUE_TYPE_COPY_STRING (7) + +union TraceValue { + bool as_bool; + unsigned long long as_uint; + long long as_int; + double as_double; + const void* as_pointer; + const char* as_string; + }; + +void XRayBrowserTraceReport(struct XRayTraceCapture* capture) { + + const void* cat_enabled = ppb_trace_event_interface->GetCategoryEnabled( + "xray"); + struct XRaySymbolTable* symbols = XRayGetSymbolTable(capture); + + int32_t thread_id = XRayGetSavedThreadID(capture); + + int head = XRayFrameGetHead(capture); + int frame = XRayFrameGetTail(capture); + while(frame != head) { + + struct XRayTimestampPair start_time = XRayFrameGetStartTimestampPair( + capture, frame); + struct XRayTimestampPair end_time = XRayFrameGetEndTimestampPair( + capture, frame); + + double pdiff = (end_time.pepper - start_time.pepper); + double odiff = (end_time.xray - start_time.xray); + double scale_a = pdiff / odiff; + double scale_b = ((double)end_time.pepper) - (scale_a * end_time.xray); + printf("Xray timestamp calibration frame %d: %f %f\n", + frame, scale_a, scale_b); + + int start = XRayFrameGetTraceStartIndex(capture, frame); + int end = XRayFrameGetTraceEndIndex(capture, frame); + + struct XRayTraceBufferEntry** stack_base = XRayMalloc( + sizeof(struct XRayTraceBufferEntry*) * (XRAY_TRACE_STACK_SIZE + 1)); + struct XRayTraceBufferEntry** stack_top = stack_base; + *stack_top = NULL; + + uint32_t num_args = 0; + const char* arg_names[] = {"annotation"}; + uint8_t arg_types[] = {TRACE_VALUE_TYPE_COPY_STRING}; + uint64_t arg_values[] = {0}; + char annotation[XRAY_TRACE_ANNOTATION_LENGTH]; + + int i; + for(i = start; i != end; i = XRayTraceNextEntry(capture, i)) { + if (XRayTraceIsAnnotation(capture, i)) { + continue; + } + + uint32_t depth = XRAY_EXTRACT_DEPTH( + XRayTraceGetEntry(capture, i)->depth_addr); + + while(*stack_top && + XRAY_EXTRACT_DEPTH((*stack_top)->depth_addr) >= depth) { + struct XRayTraceBufferEntry* e = *(stack_top--); + ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp( + 'E', cat_enabled, + XRayGetName(symbols, e), + 0, thread_id, + (scale_a * e->end_tick) + scale_b, + 0, NULL, NULL, NULL, 0 + ); + } + + num_args = 0; + struct XRayTraceBufferEntry* e = XRayTraceGetEntry(capture, i); + uint32_t annotation_index = e->annotation_index; + if (annotation_index) { + XRayTraceCopyToString(capture, annotation_index, annotation); + + union TraceValue val; + val.as_string = (const char*)annotation; + + arg_values[0] = val.as_uint; + num_args = 1; + } + + ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp( + 'B', cat_enabled, + XRayGetName(symbols, e), + 0, thread_id, + (scale_a * e->start_tick) + scale_b, + num_args, arg_names, arg_types, arg_values, 0 + ); + + *(++stack_top) = e; + } + + while(*stack_top) { + struct XRayTraceBufferEntry* e = *(stack_top--); + ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp( + 'E', cat_enabled, + XRayGetName(symbols, e), + 0, thread_id, + (scale_a * e->end_tick) + scale_b, + 0, NULL, NULL, NULL, 0 + ); + } + + frame = XRayFrameGetNext(capture, frame); + XRayFree(stack_base); + } +} + +void XRayRegisterBrowserInterface(PPB_GetInterface interface) { + ppb_trace_event_interface = (PPB_Trace_Event_Dev*)interface( + PPB_TRACE_EVENT_DEV_INTERFACE); + assert(ppb_trace_event_interface); +} + +#endif /* XRAY */ +#endif /* XRAY_DISABLE_BROWSER_INTEGRATION */ \ No newline at end of file diff --git a/hermit/usr/xray/demangle.c b/hermit/usr/xray/demangle.c new file mode 100644 index 000000000..cf3cbc43d --- /dev/null +++ b/hermit/usr/xray/demangle.c @@ -0,0 +1,25 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +#include "xray/xray_priv.h" + +/* Note name demangling requires linking against libstdc++ */ +/* If your platform does not support __cxa_demangle, re-compile XRay with: */ +/* -DXRAY_NO_DEMANGLE */ + +#if !defined(XRAY_NO_DEMANGLE) +extern +char* __cxa_demangle(const char* __mangled_name, char* __output_buffer, + size_t* __length, int* __status); +#endif + +const char* XRayDemangle(char* demangle, size_t size, const char* symbol) { +#if !defined(XRAY_NO_DEMANGLE) + int stat; + __cxa_demangle(symbol, demangle, &size, &stat); + if (stat == 0) + return demangle; +#endif + return symbol; +} diff --git a/hermit/usr/xray/hashtable.c b/hermit/usr/xray/hashtable.c new file mode 100644 index 000000000..45f2aa21c --- /dev/null +++ b/hermit/usr/xray/hashtable.c @@ -0,0 +1,205 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + + +/* Hashtable for XRay */ + +#include +#include +#include +#include +#include "xray/xray_priv.h" + +#if defined(XRAY) + +struct XRayHashTableEntry { + void* data; + uint32_t key; +}; + + +struct XRayHashTable { + int capacity; + int count; + struct XRayHashTableEntry* array; +}; + + +XRAY_NO_INSTRUMENT void XRayHashTableGrow(struct XRayHashTable* table); +XRAY_NO_INSTRUMENT uint32_t XRayHashTableHashKey(uint32_t key); +XRAY_NO_INSTRUMENT void XRayHashTableInit(struct XRayHashTable* table, + int32_t capacity); + +#define HASH_HISTO 1024 +int g_hash_histo[HASH_HISTO]; + + +/* Hashes a 32bit key into a 32bit value. */ +uint32_t XRayHashTableHashKey(uint32_t x) { + uint32_t y = x * 7919; + uint32_t z; + size_t c; + uint8_t* s = (uint8_t*)&y; + /* based on djb2 hash function */ + uint32_t h = 5381; + for (c = 0; c < sizeof(y); ++c) { + z = s[c]; + h = ((h << 5) + h) + z; + } + return h; +} + + +int XRayHashTableGetCapacity(struct XRayHashTable* table) { + return table->capacity; +} + + +int XRayHashTableGetCount(struct XRayHashTable* table) { + return table->count; +} + + +/* Looks up key in hashtable and returns blind data. */ +void* XRayHashTableLookup(struct XRayHashTable* table, uint32_t key) { + uint32_t h = XRayHashTableHashKey(key); + uint32_t m = table->capacity - 1; + uint32_t j = h & m; + uint32_t i; + int z = 1; + for (i = 0; i < m; ++i) { + /* An empty entry means the {key, data} isn't in the table. */ + if (NULL == table->array[j].data) { + ++g_hash_histo[0]; + return NULL; + } + /* Search for address */ + if (table->array[j].key == key) { + if (z >= HASH_HISTO) + z = HASH_HISTO - 1; + ++g_hash_histo[z]; + return table->array[j].data; + } + j = (j + 1) & m; + ++z; + } + /* Table was full, and there wasn't a match. */ + return NULL; +} + + +/* Inserts key & data into hash table. No duplicates. */ +void* XRayHashTableInsert(struct XRayHashTable* table, + void* data, uint32_t key) { + uint32_t h = XRayHashTableHashKey(key); + uint32_t m = table->capacity - 1; + uint32_t j = h & m; + uint32_t i; + for (i = 0; i < m; ++i) { + /* Take the first empty entry. */ + /* (the key,data isn't already in the table) */ + if (NULL == table->array[j].data) { + void* ret; + float ratio; + table->array[j].data = data; + table->array[j].key = key; + ++table->count; + ret = data; + ratio = (float)table->count / (float)table->capacity; + /* Double the capacity of the symtable if we've hit the ratio. */ + if (ratio > XRAY_SYMBOL_TABLE_MAX_RATIO) + XRayHashTableGrow(table); + return ret; + } + /* If the key is already present, return the data in the table. */ + if (table->array[j].key == key) { + return table->array[j].data; + } + j = (j + 1) & m; + } + /* Table was full */ + return NULL; +} + + +void* XRayHashTableAtIndex(struct XRayHashTable* table, int i) { + if ((i < 0) || (i >= table->capacity)) + return NULL; + return table->array[i].data; +} + + +/* Grows the hash table by doubling its capacity, */ +/* then re-inserts all the elements into the new table. */ +void XRayHashTableGrow(struct XRayHashTable* table) { + struct XRayHashTableEntry* old_array = table->array; + int old_capacity = table->capacity; + int new_capacity = old_capacity * 2; + int i; + printf("XRay: Growing a hash table...\n"); + XRayHashTableInit(table, new_capacity); + for (i = 0; i < old_capacity; ++i) { + void* data = old_array[i].data; + if (NULL != data) { + uint32_t key = old_array[i].key; + XRayHashTableInsert(table, data, key); + } + } + XRayFree(old_array); +} + + +void XRayHashTableInit(struct XRayHashTable* table, int32_t capacity) { + size_t bytes; + if (0 != (capacity & (capacity - 1))) { + printf("Xray: Hash table capacity should be a power of 2!\n"); + /* Round capacity up to next power of 2 */ + /* see http://aggregate.org/MAGIC/ */ + capacity--; + capacity |= capacity >> 1; + capacity |= capacity >> 2; + capacity |= capacity >> 4; + capacity |= capacity >> 8; + capacity |= capacity >> 16; + capacity++; + } + bytes = sizeof(table->array[0]) * capacity; + table->capacity = capacity; + table->count = 0; + table->array = (struct XRayHashTableEntry*)XRayMalloc(bytes); +} + + +/* Creates & inializes hash table. */ +struct XRayHashTable* XRayHashTableCreate(int capacity) { + struct XRayHashTable* table; + table = (struct XRayHashTable*)XRayMalloc(sizeof(*table)); + XRayHashTableInit(table, capacity); + memset(&g_hash_histo[0], 0, sizeof(g_hash_histo[0]) * HASH_HISTO); + return table; +} + + +/* Prints hash table performance to file; for debugging. */ +void XRayHashTableHisto(FILE* f) { + int i; + for (i = 0; i < HASH_HISTO; ++i) { + if (0 != g_hash_histo[i]) + fprintf(f, "hash_iterations[%d] = %d\n", i, g_hash_histo[i]); + } +} + + +/* Frees hash table. */ +/* Note: Does not free what the hash table entries point to. */ +void XRayHashTableFree(struct XRayHashTable* table) { + XRayFree(table->array); + table->capacity = 0; + table->count = 0; + table->array = NULL; + XRayFree(table); +} + +#endif /* XRAY */ + diff --git a/hermit/usr/xray/parsesymbols.c b/hermit/usr/xray/parsesymbols.c new file mode 100644 index 000000000..e2afd4413 --- /dev/null +++ b/hermit/usr/xray/parsesymbols.c @@ -0,0 +1,96 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + + +/* XRay -- a simple profiler for Native Client */ + +#include +#include +#include +#include +#include +#include "xray/xray_priv.h" + +#if defined(XRAY) + +struct XRaySymbol* XRaySymbolTableCreateEntry(struct XRaySymbolTable* symtab, + char* line) { + uint32_t addr; + unsigned int uiaddr; + char symbol_text[XRAY_LINE_SIZE]; + char* parsed_symbol; + char* newln; + if (2 != sscanf(line, "%x %1023s", &uiaddr, symbol_text)) + return NULL; + if (uiaddr > 0x07FFFFFF) { + fprintf(stderr, "While parsing the mapfile, XRay encountered:\n"); + fprintf(stderr, "%s\n", line); + fprintf(stderr, + "XRay only works with code addresses 0x00000000 - 0x07FFFFFF\n"); + fprintf(stderr, "All functions must reside in this address space.\n"); + exit(-1); + } + addr = (uint32_t)uiaddr; + parsed_symbol = strstr(line, symbol_text); + newln = strstr(parsed_symbol, "\n"); + if (NULL != newln) { + *newln = 0; + } + return XRaySymbolTableAddByName(symtab, parsed_symbol, addr); +} + + +void XRaySymbolTableParseMapfile(struct XRaySymbolTable* symtab, + const char* mapfile) { + FILE* f; + char line[XRAY_LINE_SIZE]; + bool in_text = false; + bool in_link_once = false; + int in_link_once_counter = 0; + int num_symbols = 0; + + printf("XRay: opening mapfile %s\n", mapfile); + f = fopen(mapfile, "rt"); + if (0 == f) { + fprintf(stderr, "XRay: failed to open %s\n", mapfile); + return; + } + printf("XRay: parsing...\n"); + while (NULL != fgets(line, XRAY_LINE_SIZE, f)) { + if (line == strstr(line, " .text ")) { + in_text = true; + continue; + } + if (line == strstr(line, " .gnu.linkonce.t.")) { + in_link_once = true; + in_link_once_counter = 0; + continue; + } + if (line == strstr(line, " .text.")) { + in_link_once = true; + in_link_once_counter = 0; + continue; + } + if (line == strstr(line, " 0x")) { + if (in_text) { + XRaySymbolTableCreateEntry(symtab, line); + ++num_symbols; + } else if (in_link_once) { + if (in_link_once_counter != 0) { + if (NULL != XRaySymbolTableCreateEntry(symtab, line)) + ++num_symbols; + } else { + ++in_link_once_counter; + } + } + } else { + in_text = false; + in_link_once = false; + } + } + fclose(f); + printf("XRay: parsed %d symbols into symbol table\n", num_symbols); +} + +#endif // XRAY diff --git a/hermit/usr/xray/report.c b/hermit/usr/xray/report.c new file mode 100644 index 000000000..20e9e84ac --- /dev/null +++ b/hermit/usr/xray/report.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + + +/* XRay -- a simple profiler for Native Client */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xray/xray_priv.h" + +#if defined(XRAY) + +struct XRayTotal { + int index; + int frame; + uint64_t ticks; +}; + + +/* Dumps the trace report for a given frame. */ +void XRayTraceReport(struct XRayTraceCapture* capture, + FILE* f, + int frame, + char* label, + float percent_cutoff, + int ticks_cutoff) { + int index; + int start; + int end; + float total; + char space[257]; + struct XRaySymbolTable* symbols = XRayGetSymbolTable(capture); + memset(space, ' ', 256); + space[256] = 0; + if (NULL == f) { + f = stdout; + } + fprintf(f, + "====================================================================\n"); + if (NULL != label) + fprintf(f, "label %s\n", label); + fprintf(f, "\n"); + fprintf(f, + " Address Ticks Percent Function [annotation...]\n"); + fprintf(f, + "--------------------------------------------------------------------\n"); + total = XRayFrameGetTotalTicks(capture, frame); + start = XRayFrameGetTraceStartIndex(capture, frame); + end = XRayFrameGetTraceEndIndex(capture, frame); + index = start; + while (index != end) { + if (!XRayTraceIsAnnotation(capture, index)) { + const char* symbol_name; + char annotation[XRAY_TRACE_ANNOTATION_LENGTH]; + struct XRayTraceBufferEntry* e = XRayTraceGetEntry(capture, index); + uint32_t depth = XRAY_EXTRACT_DEPTH(e->depth_addr); + uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr); + uint32_t annotation_index = e->annotation_index; + uint64_t ticks = + e->end_tick > e->start_tick ? e->end_tick - e->start_tick : 0; + float percent = 100.0f * (float)ticks / total; + if (percent >= percent_cutoff && ticks >= ticks_cutoff) { + struct XRaySymbol* symbol; + symbol = XRaySymbolTableLookup(symbols, addr); + symbol_name = XRaySymbolGetName(symbol); + if (0 != annotation_index) { + XRayTraceCopyToString(capture, annotation_index, annotation); + } else { + strcpy(annotation, ""); + } + fprintf(f, "0x%08X %12" PRIu64 " %5.1f %s%s %s\n", + (unsigned int)addr, ticks, percent, + &space[256 - depth], symbol_name, annotation); + } + } + index = XRayTraceNextEntry(capture, index); + } + fflush(f); +} + + +int qcompare(const void* a, const void* b) { + struct XRayTotal* ia = (struct XRayTotal*)a; + struct XRayTotal* ib = (struct XRayTotal*)b; + if (ib->ticks > ia->ticks) + return 1; + else if (ib->ticks < ia->ticks) + return -1; + return 0; +} + + +/* Dumps a frame report */ +void XRayFrameReport(struct XRayTraceCapture* capture, FILE* f) { + int i; + int head = XRayFrameGetHead(capture); + int frame = XRayFrameGetTail(capture); + int counter = 0; + int total_capture = 0; + struct XRayTotal* totals; + totals = (struct XRayTotal*) + alloca(XRayFrameGetCount(capture) * sizeof(struct XRayTotal)); + fprintf(f, "\n"); + fprintf(f, + "Frame# Total Ticks Capture size Annotations Label\n"); + fprintf(f, + "--------------------------------------------------------------------\n"); + while (frame != head) { + uint64_t total_ticks = XRayFrameGetTotalTicks(capture, frame); + int capture_size = XRayFrameGetTraceCount(capture, frame); + int annotation_count = XRayFrameGetAnnotationCount(capture, frame); + bool valid = XRayFrameIsValid(capture, frame); + char label[XRAY_MAX_LABEL]; + XRayFrameMakeLabel(capture, counter, label); + fprintf(f, " %3d %s %12" PRIu64 " %10d %10d %s\n", + counter, + valid ? " " : "*", + total_ticks, + capture_size, + annotation_count, + label); + totals[counter].index = counter; + totals[counter].frame = frame; + totals[counter].ticks = total_ticks; + total_capture += capture_size; + ++counter; + frame = XRayFrameGetNext(capture, frame); + } + fprintf(f, + "--------------------------------------------------------------------\n"); + fprintf(f, + "XRay: %d frame(s) %d total capture(s)\n", counter, total_capture); + fprintf(f, "\n"); + /* Sort and take average of the median cut */ + qsort(totals, counter, sizeof(struct XRayTotal), qcompare); + fprintf(f, "\n"); + fprintf(f, "Sorted by total ticks (most expensive first):\n"); + fprintf(f, "\n"); + fprintf(f, + "Frame# Total Ticks Capture size Annotations Label\n"); + fprintf(f, + "--------------------------------------------------------------------\n"); + for (i = 0; i < counter; ++i) { + int index = totals[i].index; + int frame = totals[i].frame; + uint64_t total_ticks = XRayFrameGetTotalTicks(capture, frame); + int capture_size = XRayFrameGetTraceCount(capture, frame); + int annotation_count = XRayFrameGetAnnotationCount(capture, frame); + char label[XRAY_MAX_LABEL]; + XRayFrameMakeLabel(capture, index, label); + fprintf(f, " %3d %12" PRIu64 " %10d %10d %s\n", + index, + total_ticks, + capture_size, + annotation_count, + label); + } + fflush(f); +} + + +/* Dump a frame report followed by trace report(s) for each frame. */ +void XRayReport(struct XRayTraceCapture* capture, + FILE* f, + float percent_cutoff, + int ticks_cutoff) { + int head = XRayFrameGetHead(capture); + int frame = XRayFrameGetTail(capture); + int counter = 0; + XRayFrameReport(capture, f); + fprintf(f, "\n"); + while (frame != head) { + char label[XRAY_MAX_LABEL]; + fprintf(f, "\n"); + XRayFrameMakeLabel(capture, counter, label); + XRayTraceReport(capture, f, frame, label, percent_cutoff, ticks_cutoff); + ++counter; + frame = XRayFrameGetNext(capture, frame); + } + fprintf(f, + "====================================================================\n"); +#if defined(XRAY_OUTPUT_HASH_COLLISIONS) + XRayHashTableHisto(capture, f); +#endif + fflush(f); +} + +/* Write a profile report to text file. */ +void XRaySaveReport(struct XRayTraceCapture* capture, + const char* filename, + float percent_cutoff, + int ticks_cutoff) { + FILE* f; + f = fopen(filename, "wt"); + if (NULL != f) { + XRayReport(capture, f, percent_cutoff, ticks_cutoff); + fclose(f); + } +} + +#endif /* XRAY */ diff --git a/hermit/usr/xray/stringpool.c b/hermit/usr/xray/stringpool.c new file mode 100644 index 000000000..bc8ac0956 --- /dev/null +++ b/hermit/usr/xray/stringpool.c @@ -0,0 +1,94 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + + +/* XRay string pool */ + +/* String pool holds a large pile of strings. */ +/* It is up to higher level data structures to avoid duplicates. */ +/* It is up to higher level data structures to provide fast lookups. */ + +/* _GNU_SOURCE must be defined prior to the inclusion of string.h + * so that strnlen is available with glibc */ +#define _GNU_SOURCE +#include +#include +#include "xray/xray_priv.h" + +#if defined(XRAY) + +struct XRayStringPoolNode { + struct XRayStringPoolNode* next; + char strings[XRAY_STRING_POOL_NODE_SIZE]; +}; + + +struct XRayStringPool { + struct XRayStringPoolNode* head; + struct XRayStringPoolNode* current; + int index; +}; + + +static struct XRayStringPoolNode* XRayStringPoolAllocNode() { + struct XRayStringPoolNode* s; + s = (struct XRayStringPoolNode *)XRayMalloc(sizeof(*s)); + s->next = NULL; + return s; +} + + +static int XRayStringPoolCurrentNodeSpaceAvail(struct XRayStringPool* pool) { + int i = pool->index; + return (XRAY_STRING_POOL_NODE_SIZE - i) - 1; +} + + +/* Append a string to the string pool. */ +char* XRayStringPoolAppend(struct XRayStringPool* pool, const char* src) { + /* Add +1 to STRING_POOL_NODE_SIZE to detect large strings */ + /* Add +1 to strnlen result to account for string termination */ + int n = strnlen(src, XRAY_STRING_POOL_NODE_SIZE + 1) + 1; + int a = XRayStringPoolCurrentNodeSpaceAvail(pool); + char* dst; + /* Don't accept strings larger than the pool node. */ + if (n >= (XRAY_STRING_POOL_NODE_SIZE - 1)) + return NULL; + /* If string doesn't fit, alloc a new node. */ + if (n > a) { + pool->current->next = XRayStringPoolAllocNode(); + pool->current = pool->current->next; + pool->index = 0; + } + /* Copy string and return a pointer to copy. */ + dst = &pool->current->strings[pool->index]; + strcpy(dst, src); + pool->index += n; + return dst; +} + + +/* Create & initialize a string pool instance. */ +struct XRayStringPool* XRayStringPoolCreate() { + struct XRayStringPool* pool; + pool = (struct XRayStringPool*)XRayMalloc(sizeof(*pool)); + pool->head = XRayStringPoolAllocNode(); + pool->current = pool->head; + return pool; +} + + +/* Free a string pool. */ +void XRayStringPoolFree(struct XRayStringPool* pool) { + struct XRayStringPoolNode* n = pool->head; + while (NULL != n) { + struct XRayStringPoolNode* c = n; + n = n->next; + XRayFree(c); + } + XRayFree(pool); +} + +#endif /* XRAY */ + diff --git a/hermit/usr/xray/symtable.c b/hermit/usr/xray/symtable.c new file mode 100644 index 000000000..1f0584c7f --- /dev/null +++ b/hermit/usr/xray/symtable.c @@ -0,0 +1,200 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/* XRay symbol table */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#if defined(__GLIBC__) +#include +#endif + +#include "xray/xray_priv.h" +#define PNACL_STRING_OFFSET (0x10000000) + +#if defined(XRAY) + +bool g_symtable_debug = false; + +struct XRayFrameInfo { + int times_called; + int total_ticks; +}; + + +struct XRaySymbol { + const char* name; + struct XRayFrameInfo frames[XRAY_MAX_FRAMES]; +}; + + +struct XRaySymbolPoolNode { + struct XRaySymbolPoolNode* next; + struct XRaySymbol symbols[XRAY_SYMBOL_POOL_NODE_SIZE]; +}; + + +struct XRaySymbolPool { + struct XRaySymbolPoolNode* head; + struct XRaySymbolPoolNode* current; + int index; +}; + + +struct XRaySymbolTable { + int num_symbols; + struct XRayHashTable* hash_table; + struct XRayStringPool* string_pool; + struct XRaySymbolPool* symbol_pool; +}; + + +const char* XRaySymbolGetName(struct XRaySymbol* symbol) { + return (NULL == symbol) ? "(null)" : symbol->name; +} + + +struct XRaySymbol* XRaySymbolCreate(struct XRaySymbolPool* sympool, + const char* name) +{ + struct XRaySymbol* symbol; + symbol = XRaySymbolPoolAlloc(sympool); + symbol->name = name; + return symbol; +} + + +struct XRaySymbol* XRaySymbolPoolAlloc(struct XRaySymbolPool* sympool) { + struct XRaySymbol* symbol; + if (sympool->index >= XRAY_SYMBOL_POOL_NODE_SIZE) { + struct XRaySymbolPoolNode* new_pool; + new_pool = (struct XRaySymbolPoolNode*)XRayMalloc(sizeof(*new_pool)); + sympool->current->next = new_pool; + sympool->current = new_pool; + sympool->index = 0; + } + symbol = &sympool->current->symbols[sympool->index]; + ++sympool->index; + return symbol; +} + + +struct XRaySymbolPool* XRaySymbolPoolCreate() { + struct XRaySymbolPool* sympool; + struct XRaySymbolPoolNode* node; + sympool = (struct XRaySymbolPool*)XRayMalloc(sizeof(*sympool)); + node = (struct XRaySymbolPoolNode*)XRayMalloc(sizeof(*node)); + sympool->head = node; + sympool->current = node; + sympool->index = 0; + return sympool; +} + + +void XRaySymbolPoolFree(struct XRaySymbolPool* pool) { + struct XRaySymbolPoolNode* n = pool->head; + while (NULL != n) { + struct XRaySymbolPoolNode* c = n; + n = n->next; + XRayFree(c); + } + XRayFree(pool); +} + + +int XRaySymbolTableGetCount(struct XRaySymbolTable* symtab) { + return XRayHashTableGetCount(symtab->hash_table); +} + + +struct XRaySymbol* XRaySymbolTableAtIndex(struct XRaySymbolTable* symtab, + int i) { + return (struct XRaySymbol*)XRayHashTableAtIndex(symtab->hash_table, i); +} + +struct XRaySymbol* XRaySymbolTableAdd(struct XRaySymbolTable* symtab, + struct XRaySymbol* symbol, + uint32_t addr) { + struct XRaySymbol* sym = (struct XRaySymbol*) + XRayHashTableInsert(symtab->hash_table, symbol, addr); + symtab->num_symbols = XRayHashTableGetCount(symtab->hash_table); + return sym; +} + +struct XRaySymbol* XRaySymbolTableAddByName(struct XRaySymbolTable* symtab, + const char* name, uint32_t addr) { + char* recorded_name; + struct XRaySymbol* symbol; + char buffer[XRAY_LINE_SIZE]; + const char* demangled_name = XRayDemangle(buffer, XRAY_LINE_SIZE, name); + /* record the demangled symbol name into the string pool */ + recorded_name = XRayStringPoolAppend(symtab->string_pool, demangled_name); + if (g_symtable_debug) + printf("adding symbol %s\n", recorded_name); + /* construct a symbol and put it in the symbol table */ + symbol = XRaySymbolCreate(symtab->symbol_pool, recorded_name); + return XRaySymbolTableAdd(symtab, symbol, addr); +} + +struct XRaySymbol* XRaySymbolTableLookup(struct XRaySymbolTable* symtab, + uint32_t addr) { + void *x = XRayHashTableLookup(symtab->hash_table, addr); + struct XRaySymbol* r = (struct XRaySymbol*)x; + +#if defined(__pnacl__) + if (r == NULL) { + /* Addresses are trimed to 24 bits for internal storage, so we need to + * add this offset back in order to get the real address. + */ + addr |= PNACL_STRING_OFFSET; + const char* name = (const char*)addr; + struct XRaySymbol* symbol = XRaySymbolCreate(symtab->symbol_pool, name); + r = XRaySymbolTableAdd(symtab, symbol, addr); + } +#endif + +#if defined(__GLIBC__) + if (r == NULL) { + Dl_info info; + if (dladdr((const void*)addr, &info) != 0) + if (info.dli_sname) + r = XRaySymbolTableAddByName(symtab, info.dli_sname, addr); + } +#endif + return r; +} + + +/* Returns total number of symbols in the table. */ +int XRaySymbolCount(struct XRaySymbolTable* symtab) { + return symtab->num_symbols; +} + + +/* Creates and inializes a symbol table. */ +struct XRaySymbolTable* XRaySymbolTableCreate(int size) { + struct XRaySymbolTable* symtab; + symtab = (struct XRaySymbolTable*)XRayMalloc(sizeof(*symtab)); + symtab->num_symbols = 0; + symtab->string_pool = XRayStringPoolCreate(); + symtab->hash_table = XRayHashTableCreate(size); + symtab->symbol_pool = XRaySymbolPoolCreate(); + return symtab; +} + + +/* Frees a symbol table. */ +void XRaySymbolTableFree(struct XRaySymbolTable* symtab) { + XRayStringPoolFree(symtab->string_pool); + XRaySymbolPoolFree(symtab->symbol_pool); + XRayHashTableFree(symtab->hash_table); + symtab->num_symbols = 0; + XRayFree(symtab); +} + +#endif /* XRAY */ diff --git a/hermit/usr/xray/xray.c b/hermit/usr/xray/xray.c new file mode 100644 index 000000000..9e49591fe --- /dev/null +++ b/hermit/usr/xray/xray.c @@ -0,0 +1,780 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + + +/* XRay -- a simple profiler for Native Client */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xray/xray_priv.h" + +#if defined(XRAY) + +/* GTSC - Get Time Stamp Counter */ +#if defined(__amd64__) && !defined(XRAY_NO_RDTSC) +XRAY_INLINE uint64_t RDTSC64(); +uint64_t RDTSC64() { + uint64_t a, d; + __asm__ __volatile__("rdtsc" : "=a" (a), "=d" (d)); + return ((uint64_t)a) | (((uint64_t)d) << 32); +} +#define GTSC(_x) _x = RDTSC64() +#elif defined(__i386__) && !defined(XRAY_NO_RDTSC) +#define GTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x)); +#else +XRAY_INLINE uint64_t GTOD(); +uint64_t GTOD() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; +} +#define GTSC(_x) _x = GTOD(); +#endif + +/* Use a TLS variable for cheap thread uid. */ +__thread struct XRayTraceCapture* g_xray_capture = NULL; +__thread int g_xray_thread_id_placeholder = 0; + + +struct XRayTraceStackEntry { + uint32_t depth_addr; + uint64_t tsc; + uint32_t dest; + uint32_t annotation_index; +}; + + +struct XRayTraceFrameEntry { + /* Indices into global tracebuffer */ + int start; + int end; + uint64_t start_tsc; + uint64_t end_tsc; + uint64_t total_ticks; + int annotation_count; + bool valid; + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION + struct XRayTimestampPair start_time; + struct XRayTimestampPair end_time; +#endif +}; + + +struct XRayTraceFrame { + struct XRayTraceFrameEntry* entry; + int head; + int tail; + int count; +}; + + +struct XRayTraceCapture { + /* Common variables share cache line */ + bool recording; + uint32_t stack_depth; + uint32_t max_stack_depth; + int buffer_index; + int buffer_size; + int disabled; + int annotation_count; + struct XRaySymbolTable* symbols; + bool initialized; + uint32_t annotation_filter; + uint32_t guard0; + struct XRayTraceStackEntry stack[XRAY_TRACE_STACK_SIZE] XRAY_ALIGN64; + uint32_t guard1; + uint32_t guard2; + char annotation[XRAY_ANNOTATION_STACK_SIZE] XRAY_ALIGN64; + uint32_t guard3; + struct XRayTraceBufferEntry* buffer; + struct XRayTraceFrame frame; + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION + int32_t thread_id; +#endif +} XRAY_ALIGN64; + + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__pnacl__) +XRAY_NO_INSTRUMENT void __pnacl_profile_func_enter(const char* fname); +XRAY_NO_INSTRUMENT void __pnacl_profile_func_exit(const char* fname); +#else +XRAY_NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn, + void* call_site); +XRAY_NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn, + void* call_site); +#endif + +XRAY_INLINE int XRayTraceDecrementIndexInline( + struct XRayTraceCapture* capture, int index); +XRAY_INLINE int XRayTraceIncrementIndexInline( + struct XRayTraceCapture* capture, int index); + + +XRAY_NO_INSTRUMENT void __xray_profile_append_annotation( + struct XRayTraceCapture* capture, + struct XRayTraceStackEntry* se, + struct XRayTraceBufferEntry* be); + +#ifdef __cplusplus +} +#endif + +/* Asserts that the guard values haven't changed. */ +void XRayCheckGuards(struct XRayTraceCapture* capture) { + assert(capture->guard0 == XRAY_GUARD_VALUE_0x12345678); + assert(capture->guard1 == XRAY_GUARD_VALUE_0x12345678); + assert(capture->guard2 == XRAY_GUARD_VALUE_0x87654321); + assert(capture->guard3 == XRAY_GUARD_VALUE_0x12345678); +} + +/* Decrements the trace index, wrapping around if needed. */ +int XRayTraceDecrementIndexInline( + struct XRayTraceCapture* capture, int index) { + --index; + if (index < 0) + index = capture->buffer_size - 1; + return index; +} + +/* Increments the trace index, wrapping around if needed. */ +int XRayTraceIncrementIndexInline( + struct XRayTraceCapture* capture, int index) { + ++index; + if (index >= capture->buffer_size) + index = 0; + return index; +} + +/* Returns true if the trace entry is an annotation string. */ +bool XRayTraceIsAnnotation( + struct XRayTraceCapture* capture, int index) { + struct XRayTraceBufferEntry* be = &capture->buffer[index]; + char* dst = (char*)be; + return 0 == *dst; +} + +int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) { + return XRayTraceIncrementIndexInline(capture, index); +} + +int XRayTraceDecrementIndex(struct XRayTraceCapture* capture, int index) { + return XRayTraceDecrementIndexInline(capture, index); +} + +/* The entry in the tracebuffer at index is an annotation string. */ +/* Calculate the next index value representing the next trace entry. */ +int XRayTraceSkipAnnotation(struct XRayTraceCapture* capture, int index) { + /* Annotations are strings embedded in the trace buffer. */ + /* An annotation string can span multiple trace entries. */ + /* Skip over the string by looking for zero termination. */ + assert(capture); + assert(XRayTraceIsAnnotation(capture, index)); + bool done = false; + int start_index = 1; + int i; + while (!done) { + char* str = (char*) &capture->buffer[index]; + const int num = sizeof(capture->buffer[index]); + for (i = start_index; i < num; ++i) { + if (0 == str[i]) { + done = true; + break; + } + } + index = XRayTraceIncrementIndexInline(capture, index); + start_index = 0; + } + return index; +} + + +struct XRayTraceBufferEntry* XRayTraceGetEntry( + struct XRayTraceCapture* capture, int index) { + return &capture->buffer[index]; +} + +/* Starting at index, return the index into the trace buffer */ +/* for the next trace entry. Index can wrap (ringbuffer) */ +int XRayTraceNextEntry(struct XRayTraceCapture* capture, int index) { + if (XRayTraceIsAnnotation(capture, index)) + index = XRayTraceSkipAnnotation(capture, index); + else + index = XRayTraceIncrementIndexInline(capture, index); + return index; +} + +int XRayFrameGetTraceStartIndex(struct XRayTraceCapture* capture, int frame) { + assert(capture); + assert(capture->initialized); + assert(!capture->recording); + return capture->frame.entry[frame].start; +} + +int XRayFrameGetTraceEndIndex(struct XRayTraceCapture* capture, int frame) { + assert(capture); + assert(capture->initialized); + assert(!capture->recording); + return capture->frame.entry[frame].end; +} + +/* Not very accurate, annotation strings will also be counted as "entries" */ +int XRayFrameGetTraceCount( + struct XRayTraceCapture* capture, int frame) { + assert(true == capture->initialized); + assert(frame >= 0); + assert(frame < capture->frame.count); + assert(!capture->recording); + int start = capture->frame.entry[frame].start; + int end = capture->frame.entry[frame].end; + int num; + if (start < end) + num = end - start; + else + num = capture->buffer_size - (start - end); + return num; +} + +/* Append a string to trace buffer. */ +void XRayTraceAppendString(struct XRayTraceCapture* capture, char* src) { + int index = capture->buffer_index; + bool done = false; + int start_index = 1; + int s = 0; + int i; + char* dst = (char*)&capture->buffer[index]; + const int num = sizeof(capture->buffer[index]); + dst[0] = 0; + while (!done) { + for (i = start_index; i < num; ++i) { + dst[i] = src[s]; + if (0 == src[s]) { + dst[i] = 0; + done = true; + break; + } + ++s; + } + index = XRayTraceIncrementIndexInline(capture, index); + dst = (char*)&capture->buffer[index]; + start_index = 0; + } + capture->buffer_index = index; +} + +/* Copies annotation from trace buffer to output string. */ +int XRayTraceCopyToString( + struct XRayTraceCapture* capture, int index, char* dst) { + assert(XRayTraceIsAnnotation(capture, index)); + bool done = false; + int i; + int d = 0; + int start_index = 1; + while (!done) { + char* src = (char*) &capture->buffer[index]; + const int num = sizeof(capture->buffer[index]); + for (i = start_index; i < num; ++i) { + dst[d] = src[i]; + if (0 == src[i]) { + done = true; + break; + } + ++d; + } + index = XRayTraceIncrementIndexInline(capture, index); + start_index = 0; + } + return index; +} + + +/* Generic memory malloc for XRay */ +/* validates pointer returned by malloc */ +/* memsets memory block to zero */ +void* XRayMalloc(size_t t) { + void* data; + data = calloc(1, t); + if (NULL == data) { + printf("XRay: malloc(%d) failed, panic shutdown!\n", t); + exit(-1); + } + return data; +} + + +/* Generic memory free for XRay */ +void XRayFree(void* data) { + assert(NULL != data); + free(data); +} + + +/* Main profile capture function that is called at the start */ +/* of every instrumented function. This function is implicitly */ +/* called when code is compilied with the -finstrument-functions option */ +#if defined(__pnacl__) +void __pnacl_profile_func_enter(const char* this_fn) { +#else +void __cyg_profile_func_enter(void* this_fn, void* call_site) { +#endif + struct XRayTraceCapture* capture = g_xray_capture; + if (capture && capture->recording) { + uint32_t depth = capture->stack_depth; + if (depth < capture->max_stack_depth) { + struct XRayTraceStackEntry* se = &capture->stack[depth]; + uint32_t addr = (uint32_t)(uintptr_t)this_fn; + se->depth_addr = XRAY_PACK_DEPTH_ADDR(depth, addr); + se->dest = capture->buffer_index; + se->annotation_index = 0; + GTSC(se->tsc); + capture->buffer_index = + XRayTraceIncrementIndexInline(capture, capture->buffer_index); + } + ++capture->stack_depth; + } +} + + +/* Main profile capture function that is called at the exit of */ +/* every instrumented function. This function is implicity called */ +/* when the code is compiled with the -finstrument-functions option */ +#if defined(__pnacl__) +void __pnacl_profile_func_exit(const char* this_fn) { +#else +void __cyg_profile_func_exit(void* this_fn, void* call_site) { +#endif + struct XRayTraceCapture* capture = g_xray_capture; + if (capture && capture->recording) { + --capture->stack_depth; + if (capture->stack_depth < capture->max_stack_depth) { + uint32_t depth = capture->stack_depth; + struct XRayTraceStackEntry* se = &capture->stack[depth]; + uint32_t buffer_index = se->dest; + uint64_t tsc; + struct XRayTraceBufferEntry* be = &capture->buffer[buffer_index]; + GTSC(tsc); + be->depth_addr = se->depth_addr; + be->start_tick = se->tsc; + be->end_tick = tsc; + be->annotation_index = 0; + if (0 != se->annotation_index) + __xray_profile_append_annotation(capture, se, be); + } + } +} + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION +void XRayGetTSC(uint64_t* tsc) { + GTSC(*tsc); +} + +int32_t XRayGetSavedThreadID(struct XRayTraceCapture* capture) { + return capture->thread_id; +} + +struct XRayTimestampPair XRayFrameGetStartTimestampPair( + struct XRayTraceCapture* capture, int frame) { + return capture->frame.entry[frame].start_time; +} + +struct XRayTimestampPair XRayFrameGetEndTimestampPair( + struct XRayTraceCapture* capture, int frame) { + return capture->frame.entry[frame].end_time; +} +#endif + +/* Special case appending annotation string to trace buffer */ +/* this function should only ever be called from __cyg_profile_func_exit() */ +void __xray_profile_append_annotation(struct XRayTraceCapture* capture, + struct XRayTraceStackEntry* se, + struct XRayTraceBufferEntry* be) { + struct XRayTraceStackEntry* parent = se - 1; + int start = parent->annotation_index; + be->annotation_index = capture->buffer_index; + char* str = &capture->annotation[start]; + XRayTraceAppendString(capture, str); + *str = 0; + ++capture->annotation_count; +} + + + +/* Annotates the trace buffer. no filtering. */ +void __XRayAnnotate(const char* fmt, ...) { + va_list args; + struct XRayTraceCapture* capture = g_xray_capture; + /* Only annotate functions recorded in the trace buffer. */ + if (capture && capture->initialized) { + if (0 == capture->disabled) { + if (capture->recording) { + char buffer[1024]; + int r; + va_start(args, fmt); + r = vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + { + /* Get current string ptr */ + int depth = capture->stack_depth - 1; + struct XRayTraceStackEntry* se = &capture->stack[depth]; + if (0 == se->annotation_index) { + struct XRayTraceStackEntry* parent = se - 1; + se->annotation_index = parent->annotation_index; + } + char* dst = &capture->annotation[se->annotation_index]; + strcpy(dst, buffer); + int len = strlen(dst); + se->annotation_index += len; + } + } + } + } +} + + +/* Annotates the trace buffer with user strings. Can be filtered. */ +void __XRayAnnotateFiltered(const uint32_t filter, const char* fmt, ...) { + va_list args; + struct XRayTraceCapture* capture = g_xray_capture; + if (capture && capture->initialized) { + if (0 != (filter & capture->annotation_filter)) { + if (0 == capture->disabled) { + if (capture->recording) { + char buffer[XRAY_TRACE_ANNOTATION_LENGTH]; + int r; + va_start(args, fmt); + r = vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + { + /* get current string ptr */ + int depth = capture->stack_depth - 1; + struct XRayTraceStackEntry* se = &capture->stack[depth]; + if (0 == se->annotation_index) { + struct XRayTraceStackEntry* parent = se - 1; + se->annotation_index = parent->annotation_index; + } + char* dst = &capture->annotation[se->annotation_index]; + strcpy(dst, buffer); + int len = strlen(dst); + se->annotation_index += len; + } + } + } + } + } +} + + +/* Allows user to specify annotation filter value, a 32 bit mask. */ +void XRaySetAnnotationFilter(struct XRayTraceCapture* capture, + uint32_t filter) { + capture->annotation_filter = filter; +} + + +/* Reset xray profiler. */ +void XRayReset(struct XRayTraceCapture* capture) { + assert(capture); + assert(capture->initialized); + assert(!capture->recording); + capture->buffer_index = 0; + capture->stack_depth = 0; + capture->disabled = 0; + capture->frame.head = 0; + capture->frame.tail = 0; + memset(capture->frame.entry, 0, + sizeof(capture->frame.entry[0]) * capture->frame.count); + memset(&capture->stack, 0, + sizeof(capture->stack[0]) * XRAY_TRACE_STACK_SIZE); + XRayCheckGuards(capture); +} + + +/* Change the maximum stack depth captures are made. */ +void XRaySetMaxStackDepth(struct XRayTraceCapture* capture, int stack_depth) { + assert(capture); + assert(capture->initialized); + assert(!capture->recording); + if (stack_depth < 1) + stack_depth = 1; + if (stack_depth >= XRAY_TRACE_STACK_SIZE) + stack_depth = (XRAY_TRACE_STACK_SIZE - 1); + capture->max_stack_depth = stack_depth; +} + + +int XRayFrameGetCount(struct XRayTraceCapture* capture) { + return capture->frame.count; +} + +int XRayFrameGetTail(struct XRayTraceCapture* capture) { + return capture->frame.tail; +} + +int XRayFrameGetHead(struct XRayTraceCapture* capture) { + return capture->frame.head; +} + +int XRayFrameGetPrev(struct XRayTraceCapture* capture, int i) { + i = i - 1; + if (i < 0) + i = capture->frame.count - 1; + return i; +} + +int XRayFrameGetNext(struct XRayTraceCapture* capture, int i) { + i = i + 1; + if (i >= capture->frame.count) + i = 0; + return i; +} + +bool XRayFrameIsValid(struct XRayTraceCapture* capture, int i) { + return capture->frame.entry[i].valid; +} + +uint64_t XRayFrameGetTotalTicks(struct XRayTraceCapture* capture, int i) { + return capture->frame.entry[i].total_ticks; +} + +int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) { + return capture->frame.entry[i].annotation_count; +} + +void XRayFrameMakeLabel(struct XRayTraceCapture* capture, + int counter, + char* label) { + snprintf(label, XRAY_MAX_LABEL, "@@@frame%d@@@", counter); +} + + +/* Scans the ring buffer going backwards to find last valid complete frame. */ +/* Will mark whether frames are valid or invalid during the traversal. */ +int XRayFrameFindTail(struct XRayTraceCapture* capture) { + int head = capture->frame.head; + int index = XRayFrameGetPrev(capture, head); + int total_capture = 0; + int last_valid_frame = index; + /* Check for no captures */ + if (capture->frame.head == capture->frame.tail) + return capture->frame.head; + /* Go back and invalidate all captures that have been stomped. */ + while (index != head) { + bool valid = capture->frame.entry[index].valid; + if (valid) { + total_capture += XRayFrameGetTraceCount(capture, index) + 1; + if (total_capture < capture->buffer_size) { + last_valid_frame = index; + capture->frame.entry[index].valid = true; + } else { + capture->frame.entry[index].valid = false; + } + } + index = XRayFrameGetPrev(capture, index); + } + return last_valid_frame; +} + + +/* Starts a new frame and enables capturing, and must be paired with */ +/* XRayEndFrame() Trace capturing only occurs on the thread which called */ +/* XRayBeginFrame() and each instance of capture can only trace one thread */ +/* at a time. */ +void XRayStartFrame(struct XRayTraceCapture* capture) { + int i; + assert(NULL == g_xray_capture); + assert(capture->initialized); + assert(!capture->recording); + i = capture->frame.head; + XRayCheckGuards(capture); + /* Add a trace entry marker so we can detect wrap around stomping */ + struct XRayTraceBufferEntry* be = &capture->buffer[capture->buffer_index]; + be->depth_addr = XRAY_FRAME_MARKER; + capture->buffer_index = + XRayTraceIncrementIndex(capture, capture->buffer_index); + /* Set start of the frame we're about to trace */ + capture->frame.entry[i].start = capture->buffer_index; + capture->disabled = 0; + capture->stack_depth = 1; + + /* The trace stack[0] is reserved */ + memset(&capture->stack[0], 0, sizeof(capture->stack[0])); + /* Annotation index 0 is reserved to indicate no annotation */ + capture->stack[0].annotation_index = 1; + capture->annotation[0] = 0; + capture->annotation[1] = 0; + capture->annotation_count = 0; + capture->recording = true; + GTSC(capture->frame.entry[i].start_tsc); + g_xray_capture = capture; + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION + capture->frame.entry[i].start_time = XRayGenerateTimestampsNow(); +#endif +} + + +/* Ends a frame and disables capturing. Advances to the next frame. */ +/* Must be paired with XRayStartFrame(), and called from the same thread. */ +void XRayEndFrame(struct XRayTraceCapture* capture) { + int i; + assert(capture); + assert(capture->initialized); + assert(capture->recording); + assert(g_xray_capture == capture); + assert(0 == capture->disabled); + assert(1 == capture->stack_depth); + i = capture->frame.head; + GTSC(capture->frame.entry[i].end_tsc); + capture->frame.entry[i].total_ticks = + capture->frame.entry[i].end_tsc - capture->frame.entry[i].start_tsc; + capture->recording = NULL; + capture->frame.entry[i].end = capture->buffer_index; + capture->frame.entry[i].valid = true; + capture->frame.entry[i].annotation_count = capture->annotation_count; + capture->frame.head = XRayFrameGetNext(capture, capture->frame.head); + /* If the table is filled, bump the tail. */ + if (capture->frame.head == capture->frame.tail) + capture->frame.tail = XRayFrameGetNext(capture, capture->frame.tail); + capture->frame.tail = XRayFrameFindTail(capture); + /* Check that we didn't stomp over trace entry marker. */ + int marker = XRayTraceDecrementIndex(capture, capture->frame.entry[i].start); + struct XRayTraceBufferEntry* be = &capture->buffer[marker]; + if (be->depth_addr != XRAY_FRAME_MARKER) { + fprintf(stderr, + "XRay: XRayStopFrame() detects insufficient trace buffer size!\n"); + XRayReset(capture); + } else { + /* Replace marker with an empty annotation string. */ + be->depth_addr = XRAY_NULL_ANNOTATION; + XRayCheckGuards(capture); + } + g_xray_capture = NULL; + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION + capture->frame.entry[i].end_time = XRayGenerateTimestampsNow(); +#endif +} + + +/* Get the last frame captured. Do not call while capturing. */ +/* (ie call outside of XRayStartFrame() / XRayStopFrame() pair) */ +int XRayGetLastFrame(struct XRayTraceCapture* capture) { + assert(capture); + assert(capture->initialized); + assert(!capture->recording); + assert(0 == capture->disabled); + assert(1 == capture->stack_depth); + int last_frame = XRayFrameGetPrev(capture, capture->frame.head); + return last_frame; +} + + +/* Disables capturing until a paired XRayEnableCapture() is called */ +/* This call can be nested, but must be paired with an enable */ +/* (If you need to just exclude a specific function and not its */ +/* children, the XRAY_NO_INSTRUMENT modifier might be better) */ +/* Must be called from same thread as XRayBeginFrame() / XRayEndFrame() */ +void XRayDisableCapture(struct XRayTraceCapture* capture) { + assert(capture); + assert(capture == g_xray_capture); + assert(capture->initialized); + ++capture->disabled; + capture->recording = false; +} + + +/* Re-enables capture. Must be paired with XRayDisableCapture() */ +void XRayEnableCapture(struct XRayTraceCapture* capture) { + assert(capture); + assert(capture == g_xray_capture); + assert(capture->initialized); + assert(0 < capture->disabled); + --capture->disabled; + if (0 == capture->disabled) { + capture->recording = true; + } +} + + + +struct XRaySymbolTable* XRayGetSymbolTable(struct XRayTraceCapture* capture) { + return capture->symbols; +} + + +/* Initialize XRay */ +struct XRayTraceCapture* XRayInit(int stack_depth, + int buffer_size, + int frame_count, + const char* mapfilename) { + struct XRayTraceCapture* capture; + capture = (struct XRayTraceCapture*)XRayMalloc( + sizeof(struct XRayTraceCapture)); + int adj_frame_count = frame_count + 1; + size_t buffer_size_in_bytes = + sizeof(capture->buffer[0]) * buffer_size; + size_t frame_size_in_bytes = + sizeof(capture->frame.entry[0]) * adj_frame_count; + capture->buffer = + (struct XRayTraceBufferEntry *)XRayMalloc(buffer_size_in_bytes); + capture->frame.entry = + (struct XRayTraceFrameEntry *)XRayMalloc(frame_size_in_bytes); + capture->buffer_size = buffer_size; + capture->frame.count = adj_frame_count; + capture->frame.head = 0; + capture->frame.tail = 0; + capture->disabled = 0; + capture->annotation_filter = 0xFFFFFFFF; + capture->guard0 = XRAY_GUARD_VALUE_0x12345678; + capture->guard1 = XRAY_GUARD_VALUE_0x12345678; + capture->guard2 = XRAY_GUARD_VALUE_0x87654321; + capture->guard3 = XRAY_GUARD_VALUE_0x12345678; + capture->initialized = true; + capture->recording = false; + XRaySetMaxStackDepth(capture, stack_depth); + XRayReset(capture); + + /* Mapfile is optional; we don't need it for captures, only for reports. */ + capture->symbols = + XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE); + if (NULL != mapfilename) + XRaySymbolTableParseMapfile(capture->symbols, mapfilename); + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION + /* Use the address of a thread local variable as a fake thread id. */ + capture->thread_id = (int32_t)(&g_xray_thread_id_placeholder); +#endif + + return capture; +} + + +/* Shut down and free memory used by XRay. */ +void XRayShutdown(struct XRayTraceCapture* capture) { + assert(capture); + assert(capture->initialized); + assert(!capture->recording); + XRayCheckGuards(capture); + if (NULL != capture->symbols) { + XRaySymbolTableFree(capture->symbols); + } + XRayFree(capture->frame.entry); + XRayFree(capture->buffer); + capture->initialized = false; + XRayFree(capture); +} + +#endif /* XRAY */ diff --git a/hermit/usr/xray/xray.h b/hermit/usr/xray/xray.h new file mode 100644 index 000000000..32feed0a0 --- /dev/null +++ b/hermit/usr/xray/xray.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/* XRay -- a simple profiler for Native Client */ + + +#ifndef LIBRARIES_XRAY_XRAY_H_ +#define LIBRARIES_XRAY_XRAY_H_ + +#include + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION +#include "ppapi/c/ppb.h" +#endif + +#if defined(__arm__) +#undef XRAY +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XRAY_NO_INSTRUMENT __attribute__((no_instrument_function)) +#define XRAY_INLINE __attribute__((always_inline, no_instrument_function)) + +#if defined(XRAY) + +/* Do not call __XRayAnnotate* directly; instead use the */ +/* XRayAnnotate() macros below. */ +XRAY_NO_INSTRUMENT void __XRayAnnotate(const char* str, ...) + __attribute__ ((format(printf, 1, 2))); +XRAY_NO_INSTRUMENT void __XRayAnnotateFiltered(const uint32_t filter, + const char* str, ...) __attribute__ ((format(printf, 2, 3))); + +/* This is the beginning of the public XRay API */ + +/* Ok if mapfilename is NULL, no symbols will be loaded. On glibc builds, + * XRay will also attempt to populate the symbol table with dladdr() + */ +XRAY_NO_INSTRUMENT struct XRayTraceCapture* XRayInit(int stack_size, + int buffer_size, + int frame_count, + const char* mapfilename); +XRAY_NO_INSTRUMENT void XRayShutdown(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayStartFrame(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayEndFrame(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRaySetAnnotationFilter( + struct XRayTraceCapture* capture, uint32_t filter); +XRAY_NO_INSTRUMENT void XRaySaveReport(struct XRayTraceCapture* capture, + const char* filename, + float percent_cutoff, + int cycle_cutoff); +XRAY_NO_INSTRUMENT void XRayReport(struct XRayTraceCapture* capture, + FILE* f, + float percent_cutoff, + int ticks_cutoff); + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION +XRAY_NO_INSTRUMENT void XRayBrowserTraceReport( + struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayRegisterBrowserInterface( + PPB_GetInterface get_browser_interface); +#endif /* XRAY_DISABLE_BROWSER_INTEGRATION */ + + +#if defined(XRAY_ANNOTATE) +#define XRayAnnotate(...) __XRayAnnotate(__VA_ARGS__) +#define XRayAnnotateFiltered(...) __XRayAnnotateFiltered(__VA_ARGS__) +#else +#define XRayAnnotate(...) +#define XRayAnnotateFiltered(...) +#endif +/* This is the end of the public XRay API */ + +#else /* defined(XRAY) */ + +/* Builds that don't define XRAY will use these 'null' functions instead. */ + +#define XRayAnnotate(...) +#define XRayAnnotateFiltered(...) + +inline struct XRayTraceCapture* XRayInit(int stack_size, + int buffer_size, + int frame_count, + const char* mapfilename) { + return NULL; +} +inline void XRayShutdown(struct XRayTraceCapture* capture) {} +inline void XRayStartFrame(struct XRayTraceCapture* capture) {} +inline void XRayEndFrame(struct XRayTraceCapture* capture) {} +inline void XRaySetAnnotationFilter(struct XRayTraceCapture* capture, + uint32_t filter) {} +inline void XRaySaveReport(struct XRayTraceCapture* capture, + const char* filename, + float percent_cutoff, + int cycle_cutoff) {} +inline void XRayReport(struct XRayTraceCapture* capture, + FILE* f, + float percent_cutoff, + int ticks_cutoff) {} + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION +inline void XRayBrowserTraceReport(struct XRayTraceCapture* capture) {} +inline void XRayRegisterBrowserInterface( + PPB_GetInterface get_browser_interface) {} +#endif /* XRAY_DISABLE_BROWSER_INTEGRATION */ + + +#endif /* defined(XRAY) */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBRARIES_XRAY_XRAY_H_ */ diff --git a/hermit/usr/xray/xray.odt b/hermit/usr/xray/xray.odt new file mode 100644 index 0000000000000000000000000000000000000000..a7b1deee2e707604bc647092478553f5352938ba GIT binary patch literal 52528 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

VeEnr8l`^3{dfbMUzE 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 literal 0 HcmV?d00001 diff --git a/hermit/usr/xray/xray_priv.h b/hermit/usr/xray/xray_priv.h new file mode 100644 index 000000000..714c91daa --- /dev/null +++ b/hermit/usr/xray/xray_priv.h @@ -0,0 +1,207 @@ +/* Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/* XRay -- a simple profiler for Native Client */ + +/* This header file is the private internal interface. */ + +#ifndef LIBRARIES_XRAY_XRAY_PRIV_H_ +#define LIBRARIES_XRAY_XRAY_PRIV_H_ + +#include +#include +#include +#include +#include "xray/xray.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XRAY) + +#define XRAY_FORCE_INLINE __attribute__((always_inline, no_instrument_function)) + +#define XRAY_TRACE_STACK_SIZE (256) +#define XRAY_TRACE_ANNOTATION_LENGTH (2048) +#define XRAY_TRACE_BUFFER_SIZE (1048576) +#define XRAY_ANNOTATION_STACK_SIZE ((XRAY_TRACE_STACK_SIZE) * \ + (XRAY_TRACE_ANNOTATION_LENGTH)) +#define XRAY_STRING_POOL_NODE_SIZE (32768) +#define XRAY_FRAME_MARKER (0xFFFFFFFF) +#define XRAY_NULL_ANNOTATION (0x0) +#define XRAY_FUNCTION_ALIGNMENT_BITS (4) +#define XRAY_ADDR_MASK (0xFFFFFF00) +#define XRAY_ADDR_SHIFT (4) +#define XRAY_DEPTH_MASK (0x000000FF) +#define XRAY_SYMBOL_TABLE_MAX_RATIO (0.66f) +#define XRAY_LINE_SIZE (1024) +#define XRAY_MAX_FRAMES (60) +#define XRAY_MAX_LABEL (64) +#define XRAY_DEFAULT_SYMBOL_TABLE_SIZE (4096) +#define XRAY_SYMBOL_POOL_NODE_SIZE (1024) +#define XRAY_GUARD_VALUE_0x12345678 (0x12345678) +#define XRAY_GUARD_VALUE_0x87654321 (0x87654321) +#define XRAY_EXTRACT_ADDR(x) (((x) & XRAY_ADDR_MASK) >> XRAY_ADDR_SHIFT) +#define XRAY_EXTRACT_DEPTH(x) ((x) & XRAY_DEPTH_MASK) +#define XRAY_PACK_ADDR(x) (((x) << XRAY_ADDR_SHIFT) & XRAY_ADDR_MASK) +#define XRAY_PACK_DEPTH(x) ((x) & XRAY_DEPTH_MASK) +#define XRAY_PACK_DEPTH_ADDR(d, a) (XRAY_PACK_DEPTH(d) | XRAY_PACK_ADDR(a)) +#define XRAY_ALIGN64 __attribute((aligned(64))) + +struct XRayStringPool; +struct XRayHashTable; +struct XRaySymbolPool; +struct XRaySymbol; +struct XRaySymbolTable; +struct XRayTraceCapture; + +struct XRayTraceBufferEntry { + uint32_t depth_addr; + uint32_t annotation_index; + uint64_t start_tick; + uint64_t end_tick; +}; + + +/* Important: don't instrument xray itself, so use */ +/* XRAY_NO_INSTRUMENT on all xray functions */ + +XRAY_NO_INSTRUMENT char* XRayStringPoolAppend(struct XRayStringPool* pool, + const char* src); +XRAY_NO_INSTRUMENT struct XRayStringPool* XRayStringPoolCreate(); +XRAY_NO_INSTRUMENT void XRayStringPoolFree(struct XRayStringPool* pool); + +XRAY_NO_INSTRUMENT void* XRayHashTableLookup(struct XRayHashTable* table, + uint32_t addr); +XRAY_NO_INSTRUMENT void* XRayHashTableInsert(struct XRayHashTable* table, + void* data, uint32_t addr); +XRAY_NO_INSTRUMENT void* XRayHashTableAtIndex( + struct XRayHashTable* table, int i); +XRAY_NO_INSTRUMENT int XRayHashTableGetCapacity(struct XRayHashTable* table); +XRAY_NO_INSTRUMENT int XRayHashTableGetCount(struct XRayHashTable* table); +XRAY_NO_INSTRUMENT struct XRayHashTable* XRayHashTableCreate(int capacity); +XRAY_NO_INSTRUMENT void XRayHashTableFree(struct XRayHashTable* table); +XRAY_NO_INSTRUMENT void XRayHashTableHisto(FILE* f); + +XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolPoolAlloc( + struct XRaySymbolPool* sympool); +XRAY_NO_INSTRUMENT struct XRaySymbolPool* XRaySymbolPoolCreate(); +XRAY_NO_INSTRUMENT void XRaySymbolPoolFree(struct XRaySymbolPool* sympool); + +XRAY_NO_INSTRUMENT const char* XRayDemangle(char* demangle, size_t buffersize, + const char* symbol); + +XRAY_NO_INSTRUMENT const char* XRaySymbolGetName(struct XRaySymbol* symbol); +XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolCreate( + struct XRaySymbolPool* sympool, const char* name); +XRAY_NO_INSTRUMENT void XRaySymbolFree(struct XRaySymbol* symbol); +XRAY_NO_INSTRUMENT int XRaySymbolCount(struct XRaySymbolTable* symtab); + +XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolTableCreateEntry( + struct XRaySymbolTable* symtab, char* line); +XRAY_NO_INSTRUMENT void XRaySymbolTableParseMapfile( + struct XRaySymbolTable* symbols, const char* mapfilename); + +XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolTableAddByName( + struct XRaySymbolTable* symtab, const char* name, uint32_t addr); + +XRAY_NO_INSTRUMENT int XRaySymbolTableGetCount(struct XRaySymbolTable* symtab); +XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolTableLookup( + struct XRaySymbolTable* symbols, uint32_t addr); +XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolTableAtIndex( + struct XRaySymbolTable* symbols, int i); +XRAY_NO_INSTRUMENT struct XRaySymbolTable* XRaySymbolTableCreate(int size); +XRAY_NO_INSTRUMENT void XRaySymbolTableFree(struct XRaySymbolTable* symbtab); + +XRAY_NO_INSTRUMENT struct XRaySymbolTable* XRayGetSymbolTable( + struct XRayTraceCapture* capture); + +XRAY_NO_INSTRUMENT void XRayCheckGuards(struct XRayTraceCapture* capture); + +XRAY_NO_INSTRUMENT struct XRayTraceBufferEntry* XRayTraceGetEntry( + struct XRayTraceCapture* capture, int index); +XRAY_NO_INSTRUMENT int XRayTraceIncrementIndex( + struct XRayTraceCapture* capture, int i); +XRAY_NO_INSTRUMENT int XRayTraceDecrementIndex( + struct XRayTraceCapture* capture, int i); +XRAY_NO_INSTRUMENT bool XRayTraceIsAnnotation( + struct XRayTraceCapture* capture, int index); +XRAY_NO_INSTRUMENT void XRayTraceAppendString( + struct XRayTraceCapture* capture, char* src); +XRAY_NO_INSTRUMENT int XRayTraceCopyToString( + struct XRayTraceCapture* capture, int index, char* dst); +XRAY_NO_INSTRUMENT int XRayTraceSkipAnnotation( + struct XRayTraceCapture* capture, int index); +XRAY_NO_INSTRUMENT int XRayTraceNextEntry( + struct XRayTraceCapture* capture, int index); + +XRAY_NO_INSTRUMENT void XRayFrameMakeLabel(struct XRayTraceCapture* capture, + int counter, + char* label); +XRAY_NO_INSTRUMENT int XRayFrameFindTail(struct XRayTraceCapture* capture); + +XRAY_NO_INSTRUMENT int XRayFrameGetCount(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT int XRayFrameGetHead(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT int XRayFrameGetTail(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT int XRayFrameGetNext( + struct XRayTraceCapture* capture, int index); +XRAY_NO_INSTRUMENT uint64_t XRayFrameGetTotalTicks( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT int XRayFrameGetTraceCount( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT int XRayFrameGetTraceStartIndex( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT int XRayFrameGetTraceEndIndex( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT int XRayFrameGetAnnotationCount( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT bool XRayFrameIsValid( + struct XRayTraceCapture* capture, int frame); + + +XRAY_NO_INSTRUMENT void XRayTraceReport(struct XRayTraceCapture* capture, + FILE* f, + int frame, + char* label, + float percent_cutoff, + int ticks_cutoff); +XRAY_NO_INSTRUMENT void XRayFrameReport(struct XRayTraceCapture* capture, + FILE* f); + +XRAY_NO_INSTRUMENT void* XRayMalloc(size_t t); +XRAY_NO_INSTRUMENT void XRayFree(void* data); + +XRAY_NO_INSTRUMENT void XRaySetMaxStackDepth( + struct XRayTraceCapture* capture, int stack_depth); +XRAY_NO_INSTRUMENT int XRayGetLastFrame(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayDisableCapture(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayEnableCapture(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayLoadMapfile( + struct XRayTraceCapture* capture, const char* mapfilename); + +struct XRayTimestampPair { + uint64_t xray; /* internal xray timestamp */ + int64_t pepper; /* corresponding timestamp from PPAPI interface */ +}; + +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION +XRAY_NO_INSTRUMENT void XRayGetTSC(uint64_t* tsc); +XRAY_NO_INSTRUMENT int32_t XRayGetSavedThreadID( + struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT struct XRayTimestampPair XRayFrameGetStartTimestampPair( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT struct XRayTimestampPair XRayFrameGetEndTimestampPair( + struct XRayTraceCapture* capture, int frame); +XRAY_NO_INSTRUMENT struct XRayTimestampPair XRayGenerateTimestampsNow(void); +#endif + + +#endif /* defined(XRAY) */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBRARIES_XRAY_XRAY_PRIV_H_ */ From 0e5a1ca5f9af50153af375a72446102a86e8df4e Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 00:35:35 +0200 Subject: [PATCH 2/9] xray: adaptions for HermitCore --- hermit/usr/xray/demangle.c | 2 +- hermit/usr/xray/hashtable.c | 2 +- hermit/usr/xray/parsesymbols.c | 2 +- hermit/usr/xray/report.c | 6 ++++-- hermit/usr/xray/stringpool.c | 2 +- hermit/usr/xray/symtable.c | 2 +- hermit/usr/xray/xray.c | 2 +- hermit/usr/xray/xray.h | 5 +++++ hermit/usr/xray/xray_priv.h | 2 +- 9 files changed, 16 insertions(+), 9 deletions(-) diff --git a/hermit/usr/xray/demangle.c b/hermit/usr/xray/demangle.c index cf3cbc43d..e76dd23b5 100644 --- a/hermit/usr/xray/demangle.c +++ b/hermit/usr/xray/demangle.c @@ -2,7 +2,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#include "xray/xray_priv.h" +#include "xray_priv.h" /* Note name demangling requires linking against libstdc++ */ /* If your platform does not support __cxa_demangle, re-compile XRay with: */ diff --git a/hermit/usr/xray/hashtable.c b/hermit/usr/xray/hashtable.c index 45f2aa21c..3fdd2d1c0 100644 --- a/hermit/usr/xray/hashtable.c +++ b/hermit/usr/xray/hashtable.c @@ -9,7 +9,7 @@ #include #include #include -#include "xray/xray_priv.h" +#include "xray_priv.h" #if defined(XRAY) diff --git a/hermit/usr/xray/parsesymbols.c b/hermit/usr/xray/parsesymbols.c index e2afd4413..1320ea59f 100644 --- a/hermit/usr/xray/parsesymbols.c +++ b/hermit/usr/xray/parsesymbols.c @@ -10,7 +10,7 @@ #include #include #include -#include "xray/xray_priv.h" +#include "xray_priv.h" #if defined(XRAY) diff --git a/hermit/usr/xray/report.c b/hermit/usr/xray/report.c index 20e9e84ac..a0a8d5475 100644 --- a/hermit/usr/xray/report.c +++ b/hermit/usr/xray/report.c @@ -14,7 +14,7 @@ #include #include #include -#include "xray/xray_priv.h" +#include "xray_priv.h" #if defined(XRAY) @@ -199,10 +199,12 @@ void XRaySaveReport(struct XRayTraceCapture* capture, float percent_cutoff, int ticks_cutoff) { FILE* f; - f = fopen(filename, "wt"); + f = fopen(filename, "w"); if (NULL != f) { XRayReport(capture, f, percent_cutoff, ticks_cutoff); fclose(f); + } else { + printf("Cannot open file '%s'\n", filename); } } diff --git a/hermit/usr/xray/stringpool.c b/hermit/usr/xray/stringpool.c index bc8ac0956..25ac38f02 100644 --- a/hermit/usr/xray/stringpool.c +++ b/hermit/usr/xray/stringpool.c @@ -14,7 +14,7 @@ #define _GNU_SOURCE #include #include -#include "xray/xray_priv.h" +#include "xray_priv.h" #if defined(XRAY) diff --git a/hermit/usr/xray/symtable.c b/hermit/usr/xray/symtable.c index 1f0584c7f..37edba704 100644 --- a/hermit/usr/xray/symtable.c +++ b/hermit/usr/xray/symtable.c @@ -14,7 +14,7 @@ #include #endif -#include "xray/xray_priv.h" +#include "xray_priv.h" #define PNACL_STRING_OFFSET (0x10000000) #if defined(XRAY) diff --git a/hermit/usr/xray/xray.c b/hermit/usr/xray/xray.c index 9e49591fe..dc0fe8cc7 100644 --- a/hermit/usr/xray/xray.c +++ b/hermit/usr/xray/xray.c @@ -14,7 +14,7 @@ #include #include #include -#include "xray/xray_priv.h" +#include "xray_priv.h" #if defined(XRAY) diff --git a/hermit/usr/xray/xray.h b/hermit/usr/xray/xray.h index 32feed0a0..1d459c4f3 100644 --- a/hermit/usr/xray/xray.h +++ b/hermit/usr/xray/xray.h @@ -10,6 +10,11 @@ #include +// we don't want that +#ifndef XRAY_DISABLE_BROWSER_INTEGRATION +#define XRAY_DISABLE_BROWSER_INTEGRATION +#endif + #ifndef XRAY_DISABLE_BROWSER_INTEGRATION #include "ppapi/c/ppb.h" #endif diff --git a/hermit/usr/xray/xray_priv.h b/hermit/usr/xray/xray_priv.h index 714c91daa..3aa7e5250 100644 --- a/hermit/usr/xray/xray_priv.h +++ b/hermit/usr/xray/xray_priv.h @@ -13,7 +13,7 @@ #include #include #include -#include "xray/xray.h" +#include "xray.h" #ifdef __cplusplus extern "C" { From 672a4e8d8891258bd298888c3634939eb63d4ffb Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 00:36:22 +0200 Subject: [PATCH 3/9] xray: integrate into build system --- hermit/usr/Makefile | 2 ++ hermit/usr/xray/Makefile | 26 ++++++++++++++++++++++++++ hermit/usr/xray/libxray.spec | 3 +++ 3 files changed, 31 insertions(+) create mode 100644 hermit/usr/xray/Makefile create mode 100644 hermit/usr/xray/libxray.spec diff --git a/hermit/usr/Makefile b/hermit/usr/Makefile index 5b2528c73..308d9c6ad 100644 --- a/hermit/usr/Makefile +++ b/hermit/usr/Makefile @@ -63,6 +63,7 @@ pte: libs: @echo Build OpenMP Runtime and iRCCE + $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" -C xray $Q$(MAKE) TARGET=$(TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall -pthread" -C $(OMPRT) depend $Q$(MAKE) TARGET=$(TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall -pthread" -C $(OMPRT) $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall" -C ircce depend @@ -93,6 +94,7 @@ clean: $Q$(MAKE) -C tests clean $Q$(MAKE) -C benchmarks clean $Q$(MAKE) -C openmpbench clean + $Q$(MAKE) -C xray clean veryclean: @echo Propper cleaning of the toolchain diff --git a/hermit/usr/xray/Makefile b/hermit/usr/xray/Makefile new file mode 100644 index 000000000..369ead594 --- /dev/null +++ b/hermit/usr/xray/Makefile @@ -0,0 +1,26 @@ +NEWLIB = ../x86/x86_64-hermit +CP = cp +NAME = libxray.a + +CC_FOR_TARGET ?= gcc +AR_FOR_TARGET ?= ar + +CFLAGS = -DXRAY -DXRAY_DISABLE_BROWSER_INTEGRATION -DXRAY_NO_DEMANGLE -DXRAY_ANNOTATE + +CFLAGS += ${CFLAGS_FOR_TARGET} + +OBJS = xray.o stringpool.o hashtable.o symtable.o demangle.o parsesymbols.o report.o + + +$(NAME): $(OBJS) + $(AR_FOR_TARGET) rsv $@ $(OBJS) + $(CP) $@ $(NEWLIB)/lib + $(CP) libxray.spec $(NEWLIB)/lib + $(CP) xray.h $(NEWLIB)/include + +%.o: %.c + @echo [CC] $@ + @$(CC_FOR_TARGET) $(CFLAGS) -c $< -o $@ + +clean: + rm -f *.o $(NAME) diff --git a/hermit/usr/xray/libxray.spec b/hermit/usr/xray/libxray.spec new file mode 100644 index 000000000..ee2e0d06d --- /dev/null +++ b/hermit/usr/xray/libxray.spec @@ -0,0 +1,3 @@ +# Do we really need this? Does this even what we want? +*link_xray: -lxray + From 2d25046353cc32959e1029dc52d31db7b2ee3140 Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 01:06:40 +0200 Subject: [PATCH 4/9] xray: conditionally forward compiler/linker flags to enable xray profiling You have to set the variable PROFILING to something to enable profiling using Xray. In order for profiling code to be compiled into the runtime and demo applications you must clean the whole project before. Example: $ cd HermitCore $ make clean $ make PROFILING=yes Hint: You can also export the variable (`export PROFILING=yes`) for a more permanent configuration. --- hermit/Makefile | 17 ++++++++++++++++- hermit/usr/Makefile | 21 +++++++++++---------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/hermit/Makefile b/hermit/Makefile index 363dff434..6299f1a0a 100644 --- a/hermit/Makefile +++ b/hermit/Makefile @@ -41,6 +41,19 @@ ARFLAGS = rsv RM = rm -rf OUTPUT_FORMAT = -O elf64-x86-64-hermit +# Additional flags for profiling using Xray +PROFILING_LDFLAGS = +PROFILING_CFLAGS = + +ifdef PROFILING + PROFILING_LDFLAGS = -lxray + + PROFILING_CFLAGS = -falign-functions=32 -finstrument-functions + PROFILING_CFLAGS += -finstrument-functions-exclude-function-list=_mm_pause,_mm_setcsr,_mm_getcsr # we need this for libiomp to work + PROFILING_CFLAGS += -DXRAY -DXRAY_DISABLE_BROWSER_INTEGRATION -DXRAY_NO_DEMANGLE + PROFILING_CFLAGS += -DXRAY_ANNOTATE +endif + CFLAGS_FOR_NEWLIB = -m64 -mtls-direct-seg-refs -mno-red-zone -O3 -march=native -mtune=native -ftree-vectorize $(STACKPROT) FCFLAGS_FOR_NEWLIB = -m64 -mtls-direct-seg-refs -mno-red-zone -O3 -march=native -mtune=native -ftree-vectorize FFLAGS_FOR_NEWLIB = -m64 -mtls-direct-seg-refs -mno-red-zone -O3 -march=native -mtune=native -ftree-vectorize @@ -84,7 +97,9 @@ toolchain: RANLIB_FOR_TARGET=$(RANLIB_FOR_TARGET) \ STRIP_FOR_TARGET=$(STRIP_FOR_TARGET) \ ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) \ - READELF_FOR_TARGET=$(READELF_FOR_TARGET) -C usr toolchain + READELF_FOR_TARGET=$(READELF_FOR_TARGET) \ + PROFILING_CFLAGS="$(PROFILING_CFLAGS)" \ + PROFILING_LDFLAGS="$(PROFILING_LDFLAGS)" -C usr toolchain bootstrap: $Q$(MAKE) ARCH=$(ARCH) CFLAGS="" LDFLAGS="" -C usr bootstrap diff --git a/hermit/usr/Makefile b/hermit/usr/Makefile index 308d9c6ad..9c698b168 100644 --- a/hermit/usr/Makefile +++ b/hermit/usr/Makefile @@ -26,12 +26,12 @@ default: demo: @echo Build demo applications - $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C tests depend - $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C tests - $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C benchmarks depend - $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C benchmarks + $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET) $(PROFILING_CFLAGS)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET) $(PROFILING_LDFLAGS)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C tests depend + $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET) $(PROFILING_CFLAGS)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET) $(PROFILING_LDFLAGS)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C tests + $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET) $(PROFILING_CFLAGS)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET) $(PROFILING_LDFLAGS)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C benchmarks depend + $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET) $(PROFILING_CFLAGS)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET) $(PROFILING_LDFLAGS)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C benchmarks #$Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C openmpbench depend - $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C openmpbench + $Q$(MAKE) ELFEDIT_FOR_TARGET=$(ELFEDIT_FOR_TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET) $(PROFILING_CFLAGS)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET) $(PROFILING_LDFLAGS)" OBJCOPY_FOR_TARGET=$(OBJCOPY_FOR_TARGET) -C openmpbench $(ARCH): $Q$(MKDIR) $(TMP) @@ -58,14 +58,15 @@ $(TMP)/newlib: pte: @echo Build libpthread - $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Iplatform/hermit -Iplatform/helper -Wall" -C pte depend - $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Iplatform/hermit -Iplatform/helper -Wall" -C pte + $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Iplatform/hermit -Iplatform/helper -Wall $(PROFILING_CFLAGS)" -C pte depend + $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Iplatform/hermit -Iplatform/helper -Wall $(PROFILING_CFLAGS)" -C pte libs: - @echo Build OpenMP Runtime and iRCCE + @echo Build Xray profiler $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" LDFLAGS_FOR_TARGET="$(LDFLAGS_FOR_TARGET)" -C xray - $Q$(MAKE) TARGET=$(TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall -pthread" -C $(OMPRT) depend - $Q$(MAKE) TARGET=$(TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall -pthread" -C $(OMPRT) + @echo Build OpenMP Runtime and iRCCE + $Q$(MAKE) TARGET=$(TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall -pthread $(PROFILING_CFLAGS)" -C $(OMPRT) depend + $Q$(MAKE) TARGET=$(TARGET) CXX_FOR_TARGET=$(CXX_FOR_TARGET) CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall -pthread $(PROFILING_CFLAGS)" -C $(OMPRT) $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall" -C ircce depend $Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall" -C ircce From 20f6597ef9d479750e4a249bc0a4643e478abb7b Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 01:11:13 +0200 Subject: [PATCH 5/9] benchmarks/tests: change order of linker command so that ld doesn't discard lxray --- hermit/usr/benchmarks/Makefile | 12 ++++++------ hermit/usr/tests/Makefile | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hermit/usr/benchmarks/Makefile b/hermit/usr/benchmarks/Makefile index acc0a476b..f50df1c66 100644 --- a/hermit/usr/benchmarks/Makefile +++ b/hermit/usr/benchmarks/Makefile @@ -52,7 +52,7 @@ stream.o: stream.c stream: stream.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -fopenmp -o $@ $< + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -fopenmp $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym @@ -63,21 +63,21 @@ basic.o: basic.c basic: basic.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -pthread -o $@ $< + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -pthread $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym RCCE_pingping: RCCE_pingping.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< -lircce + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -lircce $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym RCCE_pingpong: RCCE_pingpong.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< -lircce + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -lircce $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym @@ -88,14 +88,14 @@ netio.o: netio.c netio: netio.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym hg: hg.o hist.o rdtsc.o run.o init.o opt.o report.o setup.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< hist.o rdtsc.o run.o init.o opt.o report.o setup.o + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) hist.o rdtsc.o run.o init.o opt.o report.o setup.o $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym diff --git a/hermit/usr/tests/Makefile b/hermit/usr/tests/Makefile index 718794a93..376305d07 100644 --- a/hermit/usr/tests/Makefile +++ b/hermit/usr/tests/Makefile @@ -32,7 +32,7 @@ endif # other implicit rules %.o : %.c @echo [CC] $@ - $Q$(CC_FOR_TARGET) -c $(CFLAGS_FOR_TARGET) -o $@ $< + $Q$(CC_FOR_TARGET) -c $(CFLAGS_FOR_TARGET) -o $@ $< %.o: %.cpp @echo [CXX] $@ @@ -48,28 +48,28 @@ all: hello hello++ thr_hello jacobi hellof RCCE_minimum hello++: hello++.o @echo [LD] $@ - $Q$(CXX_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CXXFLAGS_FOR_TARGET) -o $@ $< + $Q$(CXX_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CXXFLAGS_FOR_TARGET) $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym hello: hello.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym hellof: hellof.o @echo [LD] $@ - $Q$(FC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(FFLAGS_FOR_TARGET) -o $@ $< + $Q$(FC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(FFLAGS_FOR_TARGET) $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym jacobi: jacobi.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< -lm + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym @@ -80,14 +80,14 @@ thr_hello.o: thr_hello.c thr_hello: thr_hello.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< -pthread + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -pthread $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym RCCE_minimum: RCCE_minimum.o @echo [LD] $@ - $Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< -lircce + $Q$(CC_FOR_TARGET) -o $@ $< $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -lircce $Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym $Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@ $Qchmod a-x $@.sym From 6e0a11373daa1056ce0d32886b3e02f4b0a00794 Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 01:19:36 +0200 Subject: [PATCH 6/9] openmpbench: implement profiling for syncbench and also change linker order --- hermit/usr/openmpbench/Makefile | 15 ++++---- hermit/usr/openmpbench/common.c | 5 +++ hermit/usr/openmpbench/syncbench.c | 55 ++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/hermit/usr/openmpbench/Makefile b/hermit/usr/openmpbench/Makefile index f3c16d8b7..7ba028b0a 100644 --- a/hermit/usr/openmpbench/Makefile +++ b/hermit/usr/openmpbench/Makefile @@ -18,8 +18,11 @@ all: syncbench schedbench taskbench prog: arraybench_$(IDA) +# We need to generate a linker map file so that Xray can resolve function names +LDFLAGS += -Wl,-Map=$@.map + syncbench: $(SYNCOBJS) - $(CC) -o syncbench $(LDFLAGS) $(SYNCOBJS) $(CLOCKOBJS) $(LIBS) -lm + $(CC) -o syncbench $(SYNCOBJS) $(LDFLAGS) $(CLOCKOBJS) $(LIBS) -lm # Rule to ensure the lower optimisation level is picked up for common.c # with the Cray compiler @@ -32,7 +35,7 @@ common_sched.o: ${CC} ${CFLAGS_CRAY} $(SCHEDFLAGS) $(OMPFLAG) -o common_sched.o -c common.c schedbench: $(SCHEDOBJS) - $(CC) -o schedbench $(LDFLAGS) $(SCHEDOBJS) $(CLOCKOBJS) $(LIBS) -lm + $(CC) -o schedbench $(SCHEDOBJS) $(LDFLAGS) $(CLOCKOBJS) $(LIBS) -lm # Multiple header files due to multiple array sizes, makes header file arraybench_*.h arraybench_$(IDA).h: arraybench.h @@ -44,13 +47,13 @@ arraybench_$(IDA).o: arraybench_$(IDA).h arraybench.c # Multiple executables due to multiple array sizes, makes exe file arraybench_* arraybench_$(IDA): $(ARRAYOBJS) $(CLOCKOBJS) arraybench.c - $(CC) $(LDFLAGS) $(ARRAYOBJS) $(CLOCKOBJS) $(LIBS) -lm -o $@ + $(CC) -o $@ $(LDFLAGS) $(ARRAYOBJS) $(CLOCKOBJS) $(LIBS) -lm taskbench: $(TASKOBJS) - $(CC) -o taskbench $(LDFLAGS) $(OMPFLAG) $(TASKOBJS) $(CLOCKOBJS) $(LIBS) -lm + $(CC) -o taskbench $(TASKOBJS) $(LDFLAGS) $(OMPFLAG) $(CLOCKOBJS) $(LIBS) -lm -clean: - -rm -rf *.o syncbench schedbench arraybench_* taskbench +clean: + -rm -rf *.o *.xray *.map syncbench schedbench arraybench_* taskbench veryclean: clean -rm -rf OpenMPBench.* *.all diff --git a/hermit/usr/openmpbench/common.c b/hermit/usr/openmpbench/common.c index 9267729d1..816795c56 100644 --- a/hermit/usr/openmpbench/common.c +++ b/hermit/usr/openmpbench/common.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "common.h" @@ -276,6 +277,8 @@ void reference(char *name, void (*refer)(void)) { int k; double start; + XRayAnnotate("name='%s'", name); + // Calculate the required number of innerreps innerreps = getinnerreps(refer); @@ -319,6 +322,8 @@ void benchmark(char *name, void (*test)(void)) intitest(name); + XRayAnnotate("name='%s'", name); + for (k=0; k<=outerreps; k++) { start = getclock(); test(); diff --git a/hermit/usr/openmpbench/syncbench.c b/hermit/usr/openmpbench/syncbench.c index b8f0d9ae6..6fa88de7f 100644 --- a/hermit/usr/openmpbench/syncbench.c +++ b/hermit/usr/openmpbench/syncbench.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "common.h" #include "syncbench.h" @@ -42,6 +43,12 @@ omp_lock_t lock; int main(int argc, char **argv) { + struct XRayTraceCapture* trace = XRayInit( + 20, // max. call depth + 32 * 1000 * 1000, // memory for report + 13, // frame count + "/hermit/usr/openmpbench/syncbench.map"); + // Start Paraver tracing #ifdef PARAVERTRACE Extrae_init(); @@ -52,48 +59,80 @@ int main(int argc, char **argv) { omp_init_lock(&lock); /* GENERATE REFERENCE TIME */ - reference("reference time 1", &refer); + XRayStartFrame(trace); + reference("reference time 1", &refer); + XRayEndFrame(trace); /* TEST PARALLEL REGION */ + XRayStartFrame(trace); benchmark("PARALLEL", &testpr); + XRayEndFrame(trace); /* TEST FOR */ - benchmark("FOR", &testfor); + XRayStartFrame(trace); + benchmark("FOR", &testfor); + XRayEndFrame(trace); /* TEST PARALLEL FOR */ - benchmark("PARALLEL FOR", &testpfor); + XRayStartFrame(trace); + benchmark("PARALLEL FOR", &testpfor); + XRayEndFrame(trace); /* TEST BARRIER */ + XRayStartFrame(trace); benchmark("BARRIER", &testbar); + XRayEndFrame(trace); /* TEST SINGLE */ + XRayStartFrame(trace); benchmark("SINGLE", &testsing); + XRayEndFrame(trace); /* TEST CRITICAL*/ + XRayStartFrame(trace); benchmark("CRITICAL", &testcrit); + XRayEndFrame(trace); /* TEST LOCK/UNLOCK */ + XRayStartFrame(trace); benchmark("LOCK/UNLOCK", &testlock); + XRayEndFrame(trace); /* TEST ORDERED SECTION */ + XRayStartFrame(trace); benchmark("ORDERED", &testorder); + XRayEndFrame(trace); /* GENERATE NEW REFERENCE TIME */ + XRayStartFrame(trace); reference("reference time 2", &referatom); + XRayEndFrame(trace); /* TEST ATOMIC */ + XRayStartFrame(trace); benchmark("ATOMIC", &testatom); + XRayEndFrame(trace); /* GENERATE NEW REFERENCE TIME */ + XRayStartFrame(trace); reference("reference time 3", &referred); + XRayEndFrame(trace); /* TEST REDUCTION (1 var) */ + XRayStartFrame(trace); benchmark("REDUCTION", &testred); + XRayEndFrame(trace); #ifdef PARAVERTRACE Extrae_fini(); #endif + XRaySaveReport(trace, + "/hermit/usr/openmpbench/syncbench.xray", // report file + 0.05f, // Only output funcs that have higher runtime [%] + 1000); // Only output funcs that have higher runtime [cycles] + XRayShutdown(trace); + finalise(); return EXIT_SUCCESS; @@ -132,6 +171,11 @@ void referred() { void testpr() { int j; +#ifdef XRAY + static int n = 1; + XRayAnnotate("n = %i", n); + n++; +#endif for (j = 0; j < innerreps; j++) { #pragma omp parallel { @@ -155,6 +199,11 @@ void testfor() { void testpfor() { int i, j; +#ifdef XRAY + static int n = 1; + XRayAnnotate("n = %i", n); + n++; +#endif for (j = 0; j < innerreps; j++) { #pragma omp parallel for for (i = 0; i < nthreads; i++) { From fcad98a10c3d13fa203e8b58ad787015500f6f2b Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 01:20:40 +0200 Subject: [PATCH 7/9] openmpbench: fix trailing whitespaces in Makefile --- hermit/usr/openmpbench/Makefile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hermit/usr/openmpbench/Makefile b/hermit/usr/openmpbench/Makefile index 7ba028b0a..937877e2f 100644 --- a/hermit/usr/openmpbench/Makefile +++ b/hermit/usr/openmpbench/Makefile @@ -6,17 +6,17 @@ CFLAGS_CRAY = ${CFLAGS} endif .c.o: - ${CC} ${CFLAGS} $(OMPFLAG) -c $*.c + ${CC} ${CFLAGS} $(OMPFLAG) -c $*.c -SYNCOBJS = syncbench.o common.o -SCHEDOBJS = schedbench.o common_sched.o -ARRAYOBJS = arraybench_$(IDA).o common.o -TASKOBJS = taskbench.o common.o +SYNCOBJS = syncbench.o common.o +SCHEDOBJS = schedbench.o common_sched.o +ARRAYOBJS = arraybench_$(IDA).o common.o +TASKOBJS = taskbench.o common.o SCHEDFLAGS = -DSCHEDBENCH all: syncbench schedbench taskbench -prog: arraybench_$(IDA) +prog: arraybench_$(IDA) # We need to generate a linker map file so that Xray can resolve function names LDFLAGS += -Wl,-Map=$@.map @@ -24,14 +24,14 @@ LDFLAGS += -Wl,-Map=$@.map syncbench: $(SYNCOBJS) $(CC) -o syncbench $(SYNCOBJS) $(LDFLAGS) $(CLOCKOBJS) $(LIBS) -lm -# Rule to ensure the lower optimisation level is picked up for common.c +# Rule to ensure the lower optimisation level is picked up for common.c # with the Cray compiler -common.o: - ${CC} ${CFLAGS_CRAY} $(OMPFLAG) -c $*.c +common.o: + ${CC} ${CFLAGS_CRAY} $(OMPFLAG) -c $*.c -# Separate rule to build common_sched.o as we need to ensure the correct -# DEFAULT_DELAY_TIME is used. -common_sched.o: +# Separate rule to build common_sched.o as we need to ensure the correct +# DEFAULT_DELAY_TIME is used. +common_sched.o: ${CC} ${CFLAGS_CRAY} $(SCHEDFLAGS) $(OMPFLAG) -o common_sched.o -c common.c schedbench: $(SCHEDOBJS) From 341d1f39d25de8df2c156c0dd957aa1faf9e1be6 Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 00:01:01 +0200 Subject: [PATCH 8/9] openmpbench: add local gitignore --- hermit/usr/openmpbench/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 hermit/usr/openmpbench/.gitignore diff --git a/hermit/usr/openmpbench/.gitignore b/hermit/usr/openmpbench/.gitignore new file mode 100644 index 000000000..403426a4c --- /dev/null +++ b/hermit/usr/openmpbench/.gitignore @@ -0,0 +1,2 @@ +*.map +*.xray From 91603343b0fdbe04b878a9d411a1f1193dd346a8 Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 18 May 2016 11:55:37 +0200 Subject: [PATCH 9/9] xray: implement frame labeling --- hermit/usr/openmpbench/common.c | 4 +-- hermit/usr/openmpbench/syncbench.c | 40 +++++++++++++++--------------- hermit/usr/xray/xray.c | 31 ++++++++++++++++++++++- hermit/usr/xray/xray.h | 3 +++ hermit/usr/xray/xray_priv.h | 5 +++- 5 files changed, 59 insertions(+), 24 deletions(-) diff --git a/hermit/usr/openmpbench/common.c b/hermit/usr/openmpbench/common.c index 816795c56..db68de713 100644 --- a/hermit/usr/openmpbench/common.c +++ b/hermit/usr/openmpbench/common.c @@ -277,7 +277,7 @@ void reference(char *name, void (*refer)(void)) { int k; double start; - XRayAnnotate("name='%s'", name); + XRayLabelFrame(name); // Calculate the required number of innerreps innerreps = getinnerreps(refer); @@ -322,7 +322,7 @@ void benchmark(char *name, void (*test)(void)) intitest(name); - XRayAnnotate("name='%s'", name); + XRayLabelFrame(name); for (k=0; k<=outerreps; k++) { start = getclock(); diff --git a/hermit/usr/openmpbench/syncbench.c b/hermit/usr/openmpbench/syncbench.c index 6fa88de7f..b3f87e093 100644 --- a/hermit/usr/openmpbench/syncbench.c +++ b/hermit/usr/openmpbench/syncbench.c @@ -68,59 +68,59 @@ int main(int argc, char **argv) { benchmark("PARALLEL", &testpr); XRayEndFrame(trace); - /* TEST FOR */ + /* TEST FOR */ XRayStartFrame(trace); benchmark("FOR", &testfor); XRayEndFrame(trace); - /* TEST PARALLEL FOR */ + /* TEST PARALLEL FOR */ XRayStartFrame(trace); benchmark("PARALLEL FOR", &testpfor); XRayEndFrame(trace); - /* TEST BARRIER */ + /* TEST BARRIER */ XRayStartFrame(trace); - benchmark("BARRIER", &testbar); + benchmark("BARRIER", &testbar); XRayEndFrame(trace); - /* TEST SINGLE */ + /* TEST SINGLE */ XRayStartFrame(trace); - benchmark("SINGLE", &testsing); + benchmark("SINGLE", &testsing); XRayEndFrame(trace); - /* TEST CRITICAL*/ + /* TEST CRITICAL*/ XRayStartFrame(trace); - benchmark("CRITICAL", &testcrit); + benchmark("CRITICAL", &testcrit); XRayEndFrame(trace); - /* TEST LOCK/UNLOCK */ + /* TEST LOCK/UNLOCK */ XRayStartFrame(trace); - benchmark("LOCK/UNLOCK", &testlock); + benchmark("LOCK/UNLOCK", &testlock); XRayEndFrame(trace); - /* TEST ORDERED SECTION */ + /* TEST ORDERED SECTION */ XRayStartFrame(trace); - benchmark("ORDERED", &testorder); + benchmark("ORDERED", &testorder); XRayEndFrame(trace); - /* GENERATE NEW REFERENCE TIME */ + /* GENERATE NEW REFERENCE TIME */ XRayStartFrame(trace); - reference("reference time 2", &referatom); + reference("reference time 2", &referatom); XRayEndFrame(trace); - /* TEST ATOMIC */ + /* TEST ATOMIC */ XRayStartFrame(trace); - benchmark("ATOMIC", &testatom); + benchmark("ATOMIC", &testatom); XRayEndFrame(trace); - /* GENERATE NEW REFERENCE TIME */ + /* GENERATE NEW REFERENCE TIME */ XRayStartFrame(trace); - reference("reference time 3", &referred); + reference("reference time 3", &referred); XRayEndFrame(trace); - /* TEST REDUCTION (1 var) */ + /* TEST REDUCTION (1 var) */ XRayStartFrame(trace); - benchmark("REDUCTION", &testred); + benchmark("REDUCTION", &testred); XRayEndFrame(trace); #ifdef PARAVERTRACE diff --git a/hermit/usr/xray/xray.c b/hermit/usr/xray/xray.c index dc0fe8cc7..6b48dcb56 100644 --- a/hermit/usr/xray/xray.c +++ b/hermit/usr/xray/xray.c @@ -97,6 +97,7 @@ struct XRayTraceCapture { uint32_t guard3; struct XRayTraceBufferEntry* buffer; struct XRayTraceFrame frame; + char frame_labels[XRAY_FRAME_LBL_BUFSIZE][XRAY_MAX_LABEL]; #ifndef XRAY_DISABLE_BROWSER_INTEGRATION int32_t thread_id; @@ -556,7 +557,30 @@ int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) { void XRayFrameMakeLabel(struct XRayTraceCapture* capture, int counter, char* label) { - snprintf(label, XRAY_MAX_LABEL, "@@@frame%d@@@", counter); + if(counter < sizeof(capture->frame_labels) && capture->frame_labels[counter][0]) { + snprintf(label, XRAY_MAX_LABEL, "%s", capture->frame_labels[counter]); + } else { + snprintf(label, XRAY_MAX_LABEL, "frame_%i", counter); + } +} +void XRayLabelFrame(const char* fmt, ...) +{ + char buffer[32]; + int r; + va_list args; + + va_start(args, fmt); + r = vsnprintf(buffer, sizeof(buffer), fmt, args); + if(r != 0) { + const int n = XRayFrameGetHead(g_xray_capture); + if(n < sizeof(g_xray_capture->frame_labels)) { + strcpy(g_xray_capture->frame_labels[n], buffer); + } else { + puts("XRay: Not enough entries in frame label buffer"); + puts(" Add -DXRAY_FRAME_LBL_BUFSIZE=[n] to your CFLAGS"); + } + } + va_end(args); } @@ -620,6 +644,11 @@ void XRayStartFrame(struct XRayTraceCapture* capture) { GTSC(capture->frame.entry[i].start_tsc); g_xray_capture = capture; + // initialize frame label + if(i < sizeof(capture->frame_labels)) { + capture->frame_labels[i][0] = 0; + } + #ifndef XRAY_DISABLE_BROWSER_INTEGRATION capture->frame.entry[i].start_time = XRayGenerateTimestampsNow(); #endif diff --git a/hermit/usr/xray/xray.h b/hermit/usr/xray/xray.h index 1d459c4f3..6e0991f0c 100644 --- a/hermit/usr/xray/xray.h +++ b/hermit/usr/xray/xray.h @@ -51,6 +51,7 @@ XRAY_NO_INSTRUMENT struct XRayTraceCapture* XRayInit(int stack_size, XRAY_NO_INSTRUMENT void XRayShutdown(struct XRayTraceCapture* capture); XRAY_NO_INSTRUMENT void XRayStartFrame(struct XRayTraceCapture* capture); XRAY_NO_INSTRUMENT void XRayEndFrame(struct XRayTraceCapture* capture); +XRAY_NO_INSTRUMENT void XRayLabelFrame(const char* fmt, ...); XRAY_NO_INSTRUMENT void XRaySetAnnotationFilter( struct XRayTraceCapture* capture, uint32_t filter); XRAY_NO_INSTRUMENT void XRaySaveReport(struct XRayTraceCapture* capture, @@ -95,6 +96,8 @@ inline struct XRayTraceCapture* XRayInit(int stack_size, inline void XRayShutdown(struct XRayTraceCapture* capture) {} inline void XRayStartFrame(struct XRayTraceCapture* capture) {} inline void XRayEndFrame(struct XRayTraceCapture* capture) {} +inline void XRayLabelFrame(const char* fmt, ...) {} + inline void XRaySetAnnotationFilter(struct XRayTraceCapture* capture, uint32_t filter) {} inline void XRaySaveReport(struct XRayTraceCapture* capture, diff --git a/hermit/usr/xray/xray_priv.h b/hermit/usr/xray/xray_priv.h index 3aa7e5250..8d2829e43 100644 --- a/hermit/usr/xray/xray_priv.h +++ b/hermit/usr/xray/xray_priv.h @@ -38,7 +38,7 @@ extern "C" { #define XRAY_SYMBOL_TABLE_MAX_RATIO (0.66f) #define XRAY_LINE_SIZE (1024) #define XRAY_MAX_FRAMES (60) -#define XRAY_MAX_LABEL (64) +#define XRAY_MAX_LABEL (32) #define XRAY_DEFAULT_SYMBOL_TABLE_SIZE (4096) #define XRAY_SYMBOL_POOL_NODE_SIZE (1024) #define XRAY_GUARD_VALUE_0x12345678 (0x12345678) @@ -197,6 +197,9 @@ XRAY_NO_INSTRUMENT struct XRayTimestampPair XRayFrameGetEndTimestampPair( XRAY_NO_INSTRUMENT struct XRayTimestampPair XRayGenerateTimestampsNow(void); #endif +#ifndef XRAY_FRAME_LBL_BUFSIZE +#define XRAY_FRAME_LBL_BUFSIZE 16 +#endif #endif /* defined(XRAY) */