| /********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| **********************************************************************/ |
| /* -*-C++-*- |
| ***************************************************************************** |
| * |
| * File: ComExeTrace.cpp |
| * Description: Common interface for all executor (run-time) traces |
| * |
| * Created: 10/26/2011 |
| * Language: C++ |
| * |
| * |
| ***************************************************************************** |
| */ |
| |
| #include "ComExeTrace.h" |
| |
| // must match with ExeTrace::FieldType, see ComExeTrace.h |
| static const char * TraceFieldTypeName[] = |
| { |
| "NOTYPE ", |
| "CHAR ", |
| "INT16 ", |
| "INT32 ", |
| "INT64 ", |
| "STRING ", |
| "PTR32 ", |
| "PTR64 ", |
| "TRANSID", // transaction id (64-bit) |
| "TMSTAMP" // time stamp |
| }; |
| |
| // not really used |
| ExeTrace::ExeTrace(char *name, void *id, void *target, |
| GetALineProcPtr getALineProc, |
| void *indexLoc, Int32 numEntries, Int32 lineLen, |
| const char *desc) |
| : traceId_(id), |
| target_(target), |
| getALineProc_(getALineProc), |
| indexLoc_(indexLoc), |
| numEntries_(numEntries), |
| lineWidth_(lineLen) |
| { |
| describes_ = (char*) malloc(strlen(desc)+1); |
| strcpy(describes_, desc); |
| strncpy(name_, name, MAX_TRACE_NAME_LEN - 1); |
| }; |
| |
| |
| // |
| // getTitleLineWidth - returned formatted line width based on the field name |
| // |
| Int32 |
| ExeTrace::getTitleLineWidth() |
| { |
| Int32 len = 0; |
| for (CollIndex i = 0; i < (UInt32) numFields_; i++) { |
| len += (strlen(fields_[i].name_) + 1); // add 1 as field separator |
| } |
| return --len; // remove the last field separator just added |
| }; |
| |
| |
| ExeTraceInfo::ExeTraceInfo() |
| : exeTraces_(NULL) // on C++ heap |
| { |
| }; |
| |
| ExeTraceInfo::~ExeTraceInfo() |
| { |
| }; |
| |
| //---------------------------------------------------------------- |
| // getExeTraceInfoAll -- query all trace info registered and save to the buffer |
| // |
| // return value: >0 - the sequence number for next trace |
| // =0 - no more trace info to return |
| // parameters: outBuf - (i/o) give buffer to store trace info |
| // maxBufLen - (i) max buffer length |
| // bufLen - (o) actual buffer size filled |
| // startTid - (i) starting trace info to query |
| // |
| // The buffer contains trace information in ascii: |
| // |
| // e.g. |
| // <trace1_name> (id=<id>): |
| // <trace_desc> |
| // Number of entries: <value> |
| // Fields: |
| // <field1_name> <data_type> |
| // <field2_name> <data_type> |
| // ... |
| // End |
| // |
| // <trace2_name>: |
| // ... |
| // |
| //---------------------------------------------------------------- |
| Int32 |
| ExeTraceInfo::getExeTraceInfoAll(char *outBuf, Int32 maxBufLen, |
| Int32 *bufLen, Int32 startTid) |
| { |
| CollIndex curr = startTid; |
| |
| Int32 len = 0; |
| *bufLen = 0; |
| if (exeTraces_.entries() <= curr) |
| return 0; // no more traces |
| |
| for (; curr < exeTraces_.entries(); curr++) |
| { |
| ExeTrace *t = exeTraces_.at(curr); |
| |
| // get the size of one exeTrace info first |
| Int32 totalSize = MAX_TRACE_NAME_LEN + 13 + sizeof(t->describes_) + 2; |
| |
| totalSize += 2 + sizeof("Number of entries: ") + 4; |
| for (Int32 i = 0; i < t->numFields_; i++) |
| { |
| // 2 tabs + field name length + field type |
| totalSize += 4 + t->fields_[i].nameLen_ + 8; |
| } |
| totalSize += 4; // plus "End" |
| |
| if (totalSize + *bufLen > maxBufLen) |
| return curr; // buffer not large enough and return what we had |
| |
| // now start dump this trace info to the buffer |
| len += sprintf((outBuf+len), |
| "%s (id=%p):\n\t%s\n\tNumber of entries: %4d\n\tFields:\n", |
| t->name_, t->traceId_, t->describes_, t->numEntries_); |
| for (Int32 i = 0; i < t->numFields_; i++) |
| { |
| len += sprintf((outBuf+len), "\t\t%s %s\n", |
| TraceFieldTypeName[t->fields_[i].fieldType_], |
| t->fields_[i].name_); |
| } |
| |
| len += sprintf((outBuf+len), "End\n"); |
| *bufLen = len; |
| } |
| |
| return (Int32) curr; |
| }; |
| |
| //---------------------------------------------------------------- |
| // getExeTraceAll -- save all registered trace data in the buffer |
| // |
| // return value: >0 - the sequence number for next trace |
| // =0 - no more trace info to return |
| // parameters: outBuf - (i/o) give buffer to store trace info |
| // maxBufLen - (i) max buffer length |
| // bufLen - (o) actual buffer size filled |
| // startTid - (i) starting trace id to query |
| // |
| // The buffer contains formatted trace data one line per trace |
| // entry, followed by trace index value |
| // |
| // e.g. |
| // <trace1_name> (nid=<nid>, pid=<pid>, <value> entries): |
| // <field1_name> <field2_name> ... |
| // <field1_value> <field2_value> ... |
| // ...... |
| // Current Index: <index> |
| // |
| // <trace2_name> (nid=<nid>, pid=<pid>, <value> entries): |
| // ... |
| // |
| // Note, given buffer outBuf should be big enough to hold data for |
| // at least one trace |
| //---------------------------------------------------------------- |
| Int32 |
| ExeTraceInfo::getExeTraceAll(char *outBuf, Int32 maxBufLen, Int32 *bufLen, |
| Int32 startTid) |
| { |
| *bufLen = 0; |
| return startTid; |
| }; |
| |
| |
| //---------------------------------------------------------------- |
| // getExeTraceId -- return trace id with given trace name |
| // return value: >0 - valid trace id |
| // =0 - no trace match the name |
| // parameters: name - trace name |
| // nameLen - length of the name |
| //---------------------------------------------------------------- |
| void * |
| ExeTraceInfo::getExeTraceId(char *name, Int32 nameLen) const |
| { |
| UInt32 noTraces = exeTraces_.entries(); |
| |
| if (noTraces) { |
| for (CollIndex i = 0; i < noTraces; i++) { |
| if (strncmp(exeTraces_[i]->getTraceName(), name, nameLen) == 0) |
| // a match |
| return exeTraces_[i]->getTraceId(); |
| } |
| // found no match |
| } |
| |
| return 0; |
| }; |
| |
| |
| //---------------------------------------------------------------- |
| // getExeTraceInfoById -- query trace parameters with given trace id |
| // return value: <0 - no trace info for this trace id |
| // =0 - trace info returned completely |
| // >0 - returned partial info only, buffer too small |
| // parameters: |
| // traceId - (i) trace id to query |
| // outBuf - (i/o) give buffer to store trace info |
| // maxBufLen - (i) max buffer length |
| // bufLen - (o) actual buffer size filled |
| // |
| // Note, the buffer contents have the same format as in getExeTraceInfoAll |
| // |
| //---------------------------------------------------------------- |
| Int32 |
| ExeTraceInfo::getExeTraceInfoById(void *traceId, char *buf, |
| Int32 maxBufLen, Int32 *bufLen) |
| { |
| return 0; |
| }; |
| |
| |
| //---------------------------------------------------------------- |
| // getExeTraceById -- retreive trace data for given trace id |
| // return value: <0 - no trace data for this trace id |
| // =0 - trace data returned |
| // >0 - returned partial data only, buffer too small |
| // parameters: |
| // traceId - (i) trace id to query |
| // outBuf - (i/o) give buffer to store trace info |
| // maxBufLen - (i) max buffer length |
| // bufLen - (o) actual buffer size filled |
| // |
| // The buffer contains formatted trace data one line per trace |
| // entry, followed by trace index value |
| // |
| // e.g. |
| // Trace ID: <id> |
| // (<trace description>) |
| // <trace1_name> (<value> entries): |
| // <field1_name> <field2_name> ... |
| // <field1_value> <field2_value> ... |
| // ...... |
| // Current Index: <index> |
| // End |
| // |
| //---------------------------------------------------------------- |
| Int32 |
| ExeTraceInfo::getExeTraceById(void *traceId, char *buf, Int32 maxBufLen, |
| Int32 *bufLen) |
| { |
| CollIndex curr = FIRST_COLL_INDEX; |
| |
| Int32 len = 0; |
| *bufLen = len; // initializing |
| |
| if (exeTraces_.entries() == 0) |
| { |
| return -1; // no more traces |
| } |
| |
| ExeTrace *t = 0; |
| for (; curr < exeTraces_.entries(); curr++) |
| { |
| t = exeTraces_.at(curr); |
| if (t->getTraceId() == traceId) |
| break; |
| } |
| |
| if (curr >= exeTraces_.entries()) |
| return -1; // no such trace |
| |
| // get the size of one exeTrace info first |
| // length of first and second lines, see above |
| Int32 totalSize = 21 + sizeof(t->describes_) + MAX_TRACE_NAME_LEN + 51; |
| // get the number of entries |
| Int32 nEntries = t->getNumEntries(); |
| |
| // the field name line |
| for (Int32 i = 0; i < t->numFields_; i++) |
| { |
| // field name length + space |
| totalSize += t->fields_[i].nameLen_ + 1; |
| } |
| totalSize += 6; // the field name line is adjusted to allow index column |
| // all lines of trace entries |
| totalSize += t->getLineWidth() + 1; // plus newline char |
| totalSize += 22; // current index |
| totalSize += 4; // plus "End" |
| |
| if (totalSize + *bufLen > maxBufLen) |
| return totalSize; // buffer not large enough and return what we had |
| |
| // now start dump this trace info to the buffer |
| if (nEntries >= 0) |
| len += sprintf((buf+len), |
| "\nTrace ID: %p\n(%s)\n%s Trace (%d entries):\n", |
| traceId, t->describes_, t->name_, nEntries); |
| else // the number of entries for this trace is not fixed |
| len += sprintf((buf+len), |
| "\nTrace ID: %p\n(%s)\n%s Trace (variable entries):\n", |
| traceId, t->describes_, t->name_); |
| |
| // field name line |
| len += sprintf((buf+len), "Indx "); |
| for (Int32 i = 0; i < t->numFields_; i++) |
| { |
| len += sprintf((buf+len), "%s ", t->fields_[i].name_); |
| } |
| len += sprintf((buf+len), "\n"); |
| |
| // print trace entries |
| Int32 j = 0, plen = 0; |
| do { |
| plen = (t->getLineProc())(t->getTarget(), j++, (buf+len)); |
| len += plen; |
| } while (plen); // keep printing until exhausted |
| |
| Int32 idx = t->getIndex(); |
| if (idx >= 0) // idx < 0 means that the trace has no cyclic buffer |
| len += sprintf((buf+len), "Current Index: %8d\n", idx); |
| len += sprintf((buf+len), "End\n"); |
| *bufLen = len; |
| |
| return 0; |
| }; |
| |
| |
| //---------------------------------------------------------------- |
| // addTrace - add trace to the trace info list |
| //---------------------------------------------------------------- |
| Int32 |
| ExeTraceInfo::addTrace(const char * traceName, void * traceId, |
| Int32 numEntries, Int32 numFields, void *target, |
| GetALineProcPtr getALineProc, void * indexLoc, |
| Int32 lineWidth, const char *desc, |
| void **exeTrace) |
| { |
| // to do: use globalheap? |
| ExeTrace *t = (ExeTrace *) malloc(sizeof(ExeTrace) + |
| numFields * sizeof(ExeTrace::TraceField)); |
| *exeTrace = 0; // set to 0 initially |
| |
| // in general, we don't like any of the followings to be 0 |
| if (!t || !traceId || !getALineProc || !numFields || !lineWidth) |
| return -1; |
| |
| // check if trace id already exists! |
| if (!isValidTraceId(traceId)) |
| return -1; |
| |
| strncpy(t->name_, traceName, MAX_TRACE_NAME_LEN-1); |
| t->name_[MAX_TRACE_NAME_LEN-1] = '\0'; |
| t->traceId_ = traceId; |
| t->target_ = target; |
| t->getALineProc_ = getALineProc; |
| t->indexLoc_ = indexLoc; |
| t->numEntries_ = numEntries; |
| t->numFields_ = numFields; |
| t->lineWidth_ = lineWidth; |
| t->describes_ = (char*) malloc(strlen(desc)+1); |
| strcpy(t->describes_, desc); |
| |
| // nullifies all field name and lenth |
| memset((char*)(t->fields_), 0, sizeof(ExeTrace::TraceField) * t->getNumFields()); |
| |
| // insert it to the list |
| exeTraces_.insert(t); |
| |
| // give the trace back to caller as reference for later use |
| *exeTrace = t; |
| |
| return 0; |
| |
| }; |
| |
| void |
| ExeTraceInfo::addTraceField(void * exeTrace, const char * name, |
| UInt32 fieldIdx, ExeTrace::FieldType fType) |
| { |
| ExeTrace *t = (ExeTrace*) exeTrace; |
| if (!isRegistered(t)) |
| return; // ignore error for now |
| if (fieldIdx >= (UInt32)t->getNumFields()) |
| return; // ignore error for now |
| strncpy(t->fields_[fieldIdx].name_, name, MAX_FIELD_NAME_LEN-1); |
| t->fields_[fieldIdx].name_[MAX_FIELD_NAME_LEN-1] = '\0'; //null terminate |
| t->fields_[fieldIdx].nameLen_ = MINOF(strlen(name), MAX_FIELD_NAME_LEN-1); |
| t->fields_[fieldIdx].fieldType_ = fType; |
| }; |
| |
| void |
| ExeTraceInfo::removeTrace(void * exeTrace) |
| { |
| ExeTrace *t = (ExeTrace*) exeTrace; |
| if (!t) |
| return; |
| if (!isRegistered(t)) |
| return; |
| |
| exeTraces_.remove(t); |
| free(t->describes_); |
| free(t); |
| }; |
| |