Blend time stamp into other work items.

The time change is usually a trivial operation, so instead carry
a timestamp on all the work items and let the work thread decide
on its own when to do a SET_TIME operation. This reduces some
pthread overhead and thus gets us some better performance.
This commit is contained in:
Stephen Williams 2010-01-08 21:46:32 -08:00
parent 06270cdd2b
commit 76ebde4cd2
3 changed files with 44 additions and 15 deletions

View File

@ -795,10 +795,18 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
static void* lxt2_thread(void*arg) static void* lxt2_thread(void*arg)
{ {
/* Keep track of the current time, and only call the set_time
function when the time changes. */
uint64_t cur_time = 0;
int run_flag = 1; int run_flag = 1;
while (run_flag) { while (run_flag) {
struct vcd_work_item_s*cell = vcd_work_thread_peek(); struct vcd_work_item_s*cell = vcd_work_thread_peek();
if (cell->time != cur_time) {
cur_time = cell->time;
lxt2_wr_set_time64(dump_file, cur_time);
}
switch (cell->type) { switch (cell->type) {
case WT_NONE: case WT_NONE:
break; break;
@ -811,16 +819,13 @@ static void* lxt2_thread(void*arg)
case WT_DUMPOFF: case WT_DUMPOFF:
lxt2_wr_set_dumpoff(dump_file); lxt2_wr_set_dumpoff(dump_file);
break; break;
case WT_SET_TIME:
lxt2_wr_set_time64(dump_file, cell->op_.val_u64);
break;
case WT_EMIT_DOUBLE: case WT_EMIT_DOUBLE:
lxt2_wr_emit_value_double(dump_file, cell->sym_.lxt2, lxt2_wr_emit_value_double(dump_file, cell->sym_.lxt2,
0, cell->op_.val_double); 0, cell->op_.val_double);
break;
case WT_EMIT_BITS: case WT_EMIT_BITS:
lxt2_wr_emit_value_bit_string(dump_file, cell->sym_.lxt2, lxt2_wr_emit_value_bit_string(dump_file, cell->sym_.lxt2,
0, cell->op_.val_char); 0, cell->op_.val_char);
free(cell->op_.val_char);
break; break;
case WT_TERMINATE: case WT_TERMINATE:
run_flag = 0; run_flag = 0;
@ -829,6 +834,7 @@ static void* lxt2_thread(void*arg)
vcd_work_thread_pop(); vcd_work_thread_pop();
} }
return 0; return 0;
} }

View File

@ -69,7 +69,6 @@ EXTERN void vcd_scope_names_delete(void);
typedef enum vcd_work_item_type_e { typedef enum vcd_work_item_type_e {
WT_NONE, WT_NONE,
WT_SET_TIME,
WT_EMIT_BITS, WT_EMIT_BITS,
WT_EMIT_DOUBLE, WT_EMIT_DOUBLE,
WT_DUMPON, WT_DUMPON,
@ -80,15 +79,21 @@ typedef enum vcd_work_item_type_e {
struct lxt2_wr_symbol; struct lxt2_wr_symbol;
# define VAL_CHAR_ARRAY_SIZE 64
struct vcd_work_item_s { struct vcd_work_item_s {
vcd_work_item_type_t type; vcd_work_item_type_t type;
uint64_t time;
union { union {
struct lxt2_wr_symbol*lxt2; struct lxt2_wr_symbol*lxt2;
} sym_; } sym_;
union { union {
double val_double; double val_double;
#ifdef VAL_CHAR_ARRAY_SIZE
char val_char[VAL_CHAR_ARRAY_SIZE];
#else
char*val_char; char*val_char;
uint64_t val_u64; #endif
} op_; } op_;
}; };

View File

@ -21,6 +21,7 @@
# include <map> # include <map>
# include <set> # include <set>
# include <string> # include <string>
# include <assert.h>
/* /*
Nexus Id cache Nexus Id cache
@ -81,7 +82,7 @@ extern "C" void vcd_scope_names_delete(void)
static pthread_t work_thread; static pthread_t work_thread;
static const unsigned WORK_QUEUE_SIZE = 512*1024; static const unsigned WORK_QUEUE_SIZE = 128*1024;
static struct vcd_work_item_s work_queue[WORK_QUEUE_SIZE]; static struct vcd_work_item_s work_queue[WORK_QUEUE_SIZE];
static volatile unsigned work_queue_next = 0; static volatile unsigned work_queue_next = 0;
static volatile unsigned work_queue_fill = 0; static volatile unsigned work_queue_fill = 0;
@ -91,6 +92,8 @@ static pthread_cond_t work_queue_is_empty_sig = PTHREAD_COND_INITIALIZER;
static pthread_cond_t work_queue_notempty_sig = PTHREAD_COND_INITIALIZER; static pthread_cond_t work_queue_notempty_sig = PTHREAD_COND_INITIALIZER;
static pthread_cond_t work_queue_notfull_sig = PTHREAD_COND_INITIALIZER; static pthread_cond_t work_queue_notfull_sig = PTHREAD_COND_INITIALIZER;
static uint64_t work_queue_next_time = 0;
struct vcd_work_item_s* vcd_work_thread_peek(void) struct vcd_work_item_s* vcd_work_thread_peek(void)
{ {
// There must always only be 1 vcd work thread, and only the // There must always only be 1 vcd work thread, and only the
@ -115,7 +118,14 @@ void vcd_work_thread_pop(void)
unsigned use_fill = work_queue_fill - 1; unsigned use_fill = work_queue_fill - 1;
work_queue_fill = use_fill; work_queue_fill = use_fill;
unsigned use_next = work_queue_next + 1; unsigned use_next = work_queue_next;
#ifndef VAL_CHAR_ARRAY_SIZE
struct vcd_work_item_s*cell = work_queue + use_next;
if (cell->type == WT_EMIT_BITS) {
free(cell->op_.val_char);
}
#endif
use_next += 1;
if (use_next >= WORK_QUEUE_SIZE) if (use_next >= WORK_QUEUE_SIZE)
use_next = 0; use_next = 0;
work_queue_next = use_next; work_queue_next = use_next;
@ -153,13 +163,17 @@ static struct vcd_work_item_s* grab_item(void)
if (cur >= WORK_QUEUE_SIZE) if (cur >= WORK_QUEUE_SIZE)
cur -= WORK_QUEUE_SIZE; cur -= WORK_QUEUE_SIZE;
return work_queue + cur; // Write the new timestamp into the work item.
struct vcd_work_item_s*cell = work_queue + cur;
cell->time = work_queue_next_time;
return cell;
} }
static void unlock_item(void) static void unlock_item(void)
{ {
work_queue_fill += 1; unsigned use_fill = work_queue_fill + 1;
if (work_queue_fill == 1) work_queue_fill = use_fill;
if (use_fill == 1)
pthread_cond_signal(&work_queue_notempty_sig); pthread_cond_signal(&work_queue_notempty_sig);
pthread_mutex_unlock(&work_queue_mutex); pthread_mutex_unlock(&work_queue_mutex);
@ -188,10 +202,7 @@ void vcd_work_dumpoff(void)
void vcd_work_set_time(uint64_t val) void vcd_work_set_time(uint64_t val)
{ {
struct vcd_work_item_s*cell = grab_item(); work_queue_next_time = val;
cell->type = WT_SET_TIME;
cell->op_.val_u64 = val;
unlock_item();
} }
void vcd_work_emit_double(struct lxt2_wr_symbol*sym, double val) void vcd_work_emit_double(struct lxt2_wr_symbol*sym, double val)
@ -205,10 +216,17 @@ void vcd_work_emit_double(struct lxt2_wr_symbol*sym, double val)
void vcd_work_emit_bits(struct lxt2_wr_symbol*sym, const char* val) void vcd_work_emit_bits(struct lxt2_wr_symbol*sym, const char* val)
{ {
struct vcd_work_item_s*cell = grab_item(); struct vcd_work_item_s*cell = grab_item();
cell->type = WT_EMIT_BITS; cell->type = WT_EMIT_BITS;
cell->sym_.lxt2 = sym; cell->sym_.lxt2 = sym;
#ifdef VAL_CHAR_ARRAY_SIZE
size_t need_len = strlen(val) + 1;
assert(need_len <= VAL_CHAR_ARRAY_SIZE);
memcpy(cell->op_.val_char, val, need_len);
#else
cell->op_.val_char = strdup(val); cell->op_.val_char = strdup(val);
#endif
unlock_item(); unlock_item();
} }