blob: 18bb7f1c2fedbb51c49536abb8e26204bb53cfd7 [file] [log] [blame]
/**********************************************************************
// @@@ 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 @@@
**********************************************************************/
#include <string.h>
#include <sys/time.h>
#include "ExSMEvent.h"
#include "ExSMCommon.h"
// Max number of events in the in-memory trace
const int EXSM_EVENT_SIZE = 1024;
// Character labels for each event type
const char *ExSMEvent::Init = "INIT";
const char *ExSMEvent::Finalize = "FINA";
const char *ExSMEvent::Register = "REGI";
const char *ExSMEvent::Cancel = "CANC";
const char *ExSMEvent::Send = "SEND";
const char *ExSMEvent::SendRetry = "SRET";
const char *ExSMEvent::Post = "POST";
const char *ExSMEvent::Receive = "RECV";
const char *ExSMEvent::Chunk = "CHNK";
const char *ExSMEvent::IDNotActive = "IDNA";
const char *ExSMEvent::ReceiveDone = "RDON";
const char *ExSMEvent::SMError = "SMER";
const char *ExSMEvent::ControlConnectionError = "CCER";
const char *ExSMEvent::Exit = "EXIT";
// struct ExSMEventTrace is a container for the in-memory trace
// associated with a given thread. Each thread (main thread and reader
// thread) will have its own instance of this structure.
struct ExSMEventTrace
{
int32_t size_;
int32_t idx_;
int32_t count_;
bool use_gettime_;
ExSMEvent *events_;
ExSMEventTrace()
: size_(0),
idx_(0),
count_(0),
use_gettime_(false),
events_(NULL)
{
}
void init()
{
if (events_ != NULL)
return;
// Should timestamps be generated with gettimeofday() or
// clock_gettime()
const char *envvar = getenv("EXSM_CLOCK_GETTIME");
if (envvar && *envvar)
use_gettime_ = true;
// Size of the array can be set with an environment variable
size_ = EXSM_EVENT_SIZE;
envvar = getenv("EXSM_EVENT_SIZE");
if (envvar && *envvar)
{
int i = atoi(envvar);
if (i > 0)
size_ = i;
}
// Allocate the array
int32_t numBytes = size_ * sizeof(ExSMEvent);
events_ = (ExSMEvent *) new char[numBytes];
memset(events_, 0, numBytes);
}
// Print all events to stdout
void print()
{
// Find the starting position
int32_t start = 0;
if (count_ >= size_)
start = idx_;
// Print the number of events
printf("\n");
printf("Number of events: %d\n", (int) count_);
// Print contents of each event. The total number of events in the
// collection is count_.
for (int32_t i = 0; i < count_; i++)
{
int32_t index = (start + i) % size_;
const ExSMEvent &e = events_[index];
const sm_target_t &t = e.target_;
const int64_t *opt = &(e.optional_[0]);
printf("[%d] %d.%09ld %s ", (int) index,
(int) e.ts_.tv_sec, (long int) e.ts_.tv_nsec, e.fn_);
printf("%d:%d:%ld :%d:0x%c ", (int) t.node, (int) t.pid, t.id,
(int) ExSMTag_GetTagWithoutQualifier(t.tag),
(char) ExSMTag_GetQualifierDisplay(t.tag));
printf("%ld %ld %ld %ld %ld\n",
opt[0], opt[1], opt[2], opt[3], opt[4]);
}
fflush(stdout);
}
};
// Thread-specific pointer to an event array
__thread ExSMEventTrace *EXSM_EVENTS = NULL;
// Global pointers to trace for main and reader threads. These are
// only used because sometimes we have had a core file in gdb and gdb
// wasn't able to display thread-local storage.
//
// Note: this naming scheme will need to change if the executor can be
// hosted in different threads during the lifetime of the process. For
// example: thread 1 executes a set of queries, then thread 1 goes
// away, then thread 2 executes another set of queries.
ExSMEventTrace EXSM_EVENTS_MAIN = ExSMEventTrace();
ExSMEventTrace EXSM_EVENTS_READER = ExSMEventTrace();
void ExSMEvent::initMainThread()
{
if (EXSM_EVENTS == NULL)
{
EXSM_EVENTS_MAIN.init();
EXSM_EVENTS = &EXSM_EVENTS_MAIN;
}
}
void ExSMEvent::initReaderThread()
{
if (EXSM_EVENTS == NULL)
{
EXSM_EVENTS_READER.init();
EXSM_EVENTS = &EXSM_EVENTS_READER;
}
}
void ExSMEvent::printMainThread()
{
EXSM_EVENTS_MAIN.print();
}
void ExSMEvent::printReaderThread()
{
EXSM_EVENTS_READER.print();
}
ExSMEvent *ExSMEvent::add(const char *fn, const sm_target_t *target,
int64_t i1, int64_t i2, int64_t i3, int64_t i4, int64_t i5)
{
if (EXSM_EVENTS == NULL)
return NULL;
ExSMEventTrace &trace = *EXSM_EVENTS;
if (trace.events_ == NULL || trace.size_ == 0)
return NULL;
// Identify the next event slot
ExSMEvent &event = trace.events_[trace.idx_];
memset(&event, 0, sizeof(event));
// Store a timestamp in the event
if (trace.use_gettime_)
{
clock_gettime(CLOCK_MONOTONIC, &event.ts_);
}
else
{
struct timeval tv;
gettimeofday(&tv, NULL);
event.ts_.tv_sec = tv.tv_sec;
event.ts_.tv_nsec = tv.tv_usec * 1000;
}
// Copy all arguments into the event
if (fn)
strncpy(event.fn_, fn, 4);
if (target)
event.target_ = *target;
event.optional_[0] = i1;
event.optional_[1] = i2;
event.optional_[2] = i3;
event.optional_[3] = i4;
event.optional_[4] = i5;
// Move idx_ to the next available slot
trace.idx_ = ((trace.idx_ + 1) % trace.size_);
// Keep a count of how many events are in the trace
if (trace.count_ < trace.size_)
trace.count_++;
return &event;
}