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:
parent
06270cdd2b
commit
76ebde4cd2
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue