| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #include "TraceLogging.h" |
| #include <cstdarg> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdint.h> |
| |
| using namespace js; |
| |
| #ifndef TRACE_LOG_DIR |
| # if defined(_WIN32) |
| # define TRACE_LOG_DIR "" |
| # else |
| # define TRACE_LOG_DIR "/tmp/" |
| # endif |
| #endif |
| |
| #if defined(__i386__) |
| static __inline__ uint64_t |
| js::rdtsc(void) |
| { |
| uint64_t x; |
| __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); |
| return x; |
| } |
| #elif defined(__x86_64__) |
| static __inline__ uint64_t |
| js::rdtsc(void) |
| { |
| unsigned hi, lo; |
| __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); |
| return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 ); |
| } |
| #elif defined(__powerpc__) |
| static __inline__ uint64_t |
| js::rdtsc(void) |
| { |
| uint64_t result=0; |
| uint32_t upper, lower,tmp; |
| __asm__ volatile( |
| "0: \n" |
| "\tmftbu %0 \n" |
| "\tmftb %1 \n" |
| "\tmftbu %2 \n" |
| "\tcmpw %2,%0 \n" |
| "\tbne 0b \n" |
| : "=r"(upper),"=r"(lower),"=r"(tmp) |
| ); |
| result = upper; |
| result = result<<32; |
| result = result|lower; |
| |
| return(result); |
| } |
| #else |
| static __inline__ uint64_t |
| rdtsc(void) |
| { |
| return 0; |
| } |
| #endif |
| |
| const char* const TraceLogging::type_name[] = { |
| "start,ion_compile", |
| "stop,ion_compile", |
| "start,ion_cannon", |
| "stop,ion_cannon", |
| "stop,ion_cannon_bailout", |
| "start,ion_side_cannon", |
| "stop,ion_side_cannon", |
| "stop,ion_side_cannon_bailout", |
| "start,yarr_jit_execute", |
| "stop,yarr_jit_execute", |
| "start,jm_safepoint", |
| "stop,jm_safepoint", |
| "start,jm_normal", |
| "stop,jm_normal", |
| "start,jm_compile", |
| "stop,jm_compile", |
| "start,gc", |
| "stop,gc", |
| "start,interpreter", |
| "stop,interpreter" |
| }; |
| TraceLogging* TraceLogging::_defaultLogger = NULL; |
| |
| TraceLogging::TraceLogging() |
| : loggingTime(0), |
| entries(NULL), |
| curEntry(0), |
| numEntries(1000000), |
| fileno(0), |
| out(NULL) |
| { |
| } |
| |
| TraceLogging::~TraceLogging() |
| { |
| if (out != NULL) { |
| fclose(out); |
| out = NULL; |
| } |
| |
| if (entries != NULL) { |
| flush(); |
| js_free(entries); |
| entries = NULL; |
| } |
| } |
| |
| void |
| TraceLogging::grow() |
| { |
| Entry* nentries = (Entry*) js_realloc(entries, numEntries*2*sizeof(Entry)); |
| |
| // Allocating a bigger array failed. |
| // Keep using the current storage, but remove all entries by flushing them. |
| if (nentries == NULL) { |
| flush(); |
| return; |
| } |
| |
| entries = nentries; |
| numEntries *= 2; |
| } |
| |
| void |
| TraceLogging::log(Type type, const char* file, unsigned int lineno) |
| { |
| uint64_t now = rdtsc(); |
| |
| // Create array containing the entries if not existing. |
| if (entries == NULL) { |
| entries = (Entry*) js_malloc(numEntries*sizeof(Entry)); |
| if (entries == NULL) |
| return; |
| } |
| |
| // Copy the logging information, |
| // because original could already be freed before writing the log file. |
| char *copy = NULL; |
| if (file != NULL) |
| copy = strdup(file); |
| |
| entries[curEntry++] = Entry(now - loggingTime, copy, lineno, type); |
| |
| // Increase length when not enough place in the array |
| if (curEntry >= numEntries) |
| grow(); |
| |
| // Save the time spend logging the information in order to discard this time from the logged time. |
| // Especially needed when increasing the array or flushing the information. |
| loggingTime += rdtsc()-now; |
| } |
| |
| void |
| TraceLogging::log(Type type, JSScript* script) |
| { |
| this->log(type, script->filename(), script->lineno); |
| } |
| |
| void |
| TraceLogging::log(const char* log) |
| { |
| this->log(INFO, log, 0); |
| } |
| |
| void |
| TraceLogging::log(Type type) |
| { |
| this->log(type, NULL, 0); |
| } |
| |
| void |
| TraceLogging::flush() |
| { |
| // Open the logging file, when not opened yet. |
| if (out == NULL) |
| out = fopen(TRACE_LOG_DIR "tracelogging.log", "w"); |
| |
| // Print all log entries into the file |
| for (unsigned int i = 0; i < curEntry; i++) { |
| int written; |
| if (entries[i].type() == INFO) { |
| written = fprintf(out, "INFO,%s\n", entries[i].file()); |
| } else { |
| if (entries[i].file() == NULL) { |
| written = fprintf(out, "%llu,%s\n", |
| (unsigned long long)entries[i].tick(), |
| type_name[entries[i].type()]); |
| } else { |
| written = fprintf(out, "%llu,%s,%s:%d\n", |
| (unsigned long long)entries[i].tick(), |
| type_name[entries[i].type()], |
| entries[i].file(), |
| entries[i].lineno()); |
| } |
| } |
| |
| // A logging file can only be 2GB of length (fwrite limit). |
| // When we exceed this limit, the writing will fail. |
| // In that case try creating a extra file to write the log entries. |
| if (written < 0) { |
| fclose(out); |
| if (fileno >= 9999) |
| exit(-1); |
| |
| char filename[21 + sizeof(TRACE_LOG_DIR)]; |
| sprintf (filename, TRACE_LOG_DIR "tracelogging-%d.log", ++fileno); |
| out = fopen(filename, "w"); |
| i--; // Try to print message again |
| continue; |
| } |
| |
| if (entries[i].file() != NULL) { |
| js_free(entries[i].file()); |
| entries[i].file_ = NULL; |
| } |
| } |
| curEntry = 0; |
| } |
| |
| TraceLogging* |
| TraceLogging::defaultLogger() |
| { |
| if (_defaultLogger == NULL) { |
| _defaultLogger = new TraceLogging(); |
| atexit (releaseDefaultLogger); |
| } |
| return _defaultLogger; |
| } |
| |
| void |
| TraceLogging::releaseDefaultLogger() |
| { |
| if (_defaultLogger != NULL) { |
| delete _defaultLogger; |
| _defaultLogger = NULL; |
| } |
| } |
| |
| /* Helper functions for asm calls */ |
| void |
| js::TraceLog(TraceLogging* logger, TraceLogging::Type type, JSScript* script) |
| { |
| logger->log(type, script); |
| } |
| |
| void |
| js::TraceLog(TraceLogging* logger, const char* log) |
| { |
| logger->log(log); |
| } |
| |
| void |
| js::TraceLog(TraceLogging* logger, TraceLogging::Type type) |
| { |
| logger->log(type); |
| } |