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)
{
/* 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;
while (run_flag) {
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) {
case WT_NONE:
break;
@ -811,16 +819,13 @@ static void* lxt2_thread(void*arg)
case WT_DUMPOFF:
lxt2_wr_set_dumpoff(dump_file);
break;
case WT_SET_TIME:
lxt2_wr_set_time64(dump_file, cell->op_.val_u64);
break;
case WT_EMIT_DOUBLE:
lxt2_wr_emit_value_double(dump_file, cell->sym_.lxt2,
0, cell->op_.val_double);
break;
case WT_EMIT_BITS:
lxt2_wr_emit_value_bit_string(dump_file, cell->sym_.lxt2,
0, cell->op_.val_char);
free(cell->op_.val_char);
break;
case WT_TERMINATE:
run_flag = 0;
@ -829,6 +834,7 @@ static void* lxt2_thread(void*arg)
vcd_work_thread_pop();
}
return 0;
}

View File

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

View File

@ -21,6 +21,7 @@
# include <map>
# include <set>
# include <string>
# include <assert.h>
/*
Nexus Id cache
@ -81,7 +82,7 @@ extern "C" void vcd_scope_names_delete(void)
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 volatile unsigned work_queue_next = 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_notfull_sig = PTHREAD_COND_INITIALIZER;
static uint64_t work_queue_next_time = 0;
struct vcd_work_item_s* vcd_work_thread_peek(void)
{
// 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;
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)
use_next = 0;
work_queue_next = use_next;
@ -153,13 +163,17 @@ static struct vcd_work_item_s* grab_item(void)
if (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)
{
work_queue_fill += 1;
if (work_queue_fill == 1)
unsigned use_fill = work_queue_fill + 1;
work_queue_fill = use_fill;
if (use_fill == 1)
pthread_cond_signal(&work_queue_notempty_sig);
pthread_mutex_unlock(&work_queue_mutex);
@ -188,10 +202,7 @@ void vcd_work_dumpoff(void)
void vcd_work_set_time(uint64_t val)
{
struct vcd_work_item_s*cell = grab_item();
cell->type = WT_SET_TIME;
cell->op_.val_u64 = val;
unlock_item();
work_queue_next_time = 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)
{
struct vcd_work_item_s*cell = grab_item();
cell->type = WT_EMIT_BITS;
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);
#endif
unlock_item();
}