emview_analysis.c from EmStar at Krugle
Show emview_analysis.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "emview_i.h"
QUEUE_INST(emview_consumer_list, _, consumers, consumer_t, consumer_list_t);
consumer_t *emview_consumer_create(consumer_list_t *cl, void *data, emview_consumer_cb cb)
{
static int next_handle = 1;
consumer_t *c = g_new0(consumer_t, 1);
c->handle = (next_handle++);
c->data = data;
c->cb = cb;
emview_consumer_list_push(cl, c);
return c;
}
void emview_consumer_destroy(consumer_list_t *cl, consumer_t *c)
{
if (c) {
if (cl)
emview_consumer_list_remove(cl, c);
free(c);
}
}
void emview_consumer_list_destroy(consumer_list_t *cl)
{
while (emview_consumer_list_top(cl))
emview_consumer_destroy(cl, emview_consumer_list_top(cl));
}
static int emview_analysis_timer_fired(void *data, int interval, g_event_t *event)
{
consumer_t *c;
analysis_timer_t *timer = (analysis_timer_t *)data;
/* trigger all the consumers */
for (c = emview_consumer_list_top(&timer->consumer_list);
c; c = emview_consumer_list_next(c)) {
if (c->cb) c->cb(c->data, 0, timer->fire_count, c->handle);
}
/* increment the fire count */
timer->fire_count++;
/* $$$ doesn't really attempt absolute timer boundaries */
return TIMER_RENEW;
}
analysis_timer_t *emview_analysis_timer_lookup_or_create(analysis_info_t *a, int interval, int offset)
{
int hole = -1;
int i;
for (i=0; i<MAX_ANALYSIS_TIMERS; i++) {
if (a->timers[i].interval == 0) {
if (hole < 0) hole = i;
continue;
}
if ((a->timers[i].interval == interval) && (a->timers[i].phase_offset == offset))
return &(a->timers[i]);
}
/* create? */
if (hole >= 0) {
memset(&(a->timers[hole]), 0, sizeof(a->timers[hole]));
a->timers[hole].index = hole;
a->timers[hole].interval = interval;
a->timers[hole].phase_offset = offset;
/* $$ offset is not currently supported, and timers aren't set to sync precisely with sim start */
g_timer_add(interval, emview_analysis_timer_fired, &(a->timers[hole]), NULL, &(a->timers[hole].timer));
return &(a->timers[hole]);
}
return NULL;
}
void emview_analysis_clear_all(analysis_info_t *a)
{
int i;
for (i=0; i<MAX_ANALYSIS_TIMERS; i++) {
g_event_destroy(a->timers[i].timer);
emview_consumer_list_destroy(&(a->timers[i].consumer_list));
}
memset(a->timers, 0, sizeof(a->timers));
}
/* API call, allows module to register a timer, returns handle */
int emview_timer_source_register(int interval, int offset,
emview_consumer_cb cb, void *data)
{
int handle = -1;
analysis_timer_t *timer;
if (interval == 0) {
elog(LOG_WARNING, "Analysis timer interval cannot be 0");
goto out;
}
/* locate a timer */
timer = emview_analysis_timer_lookup_or_create(&(_core.analysis), interval, offset);
if (timer == NULL) {
elog(LOG_WARNING, "No room to add new analysis timer");
goto out;
}
/* add new client */
if (emview_consumer_create(&(timer->consumer_list), data, cb) == NULL)
elog(LOG_WARNING, "Failed to add new analysis timer consumer");
out:
return handle;
}
int emview_timer_source_unregister(int handle)
{
int i;
/* search for timer source */
for (i=0; i<MAX_ANALYSIS_TIMERS; i++) {
if (_core.analysis.timers[i].timer) {
consumer_t *c;
for (c = emview_consumer_list_top(&_core.analysis.timers[i].consumer_list);
c; c = emview_consumer_list_next(c)) {
if (c->handle == handle) {
emview_consumer_destroy(&_core.analysis.timers[i].consumer_list, c);
return 0;
}
}
}
}
return -1;
}
void emview_analysis_restart(analysis_info_t *a)
{
if (a->last_nonce) {
/* call close callbacks */
emview_module_t *mod;
for (mod = emview_module_top(&_core); mod; mod = emview_module_next(mod)) {
if (mod->opts.analysis_close) {
int i;
for (i=0; i<emview_mod_inst_count(mod); i++) {
emview_module_inst_t *inst = emview_mod_inst_index(mod, i);
mod->opts.analysis_close(mod, inst);
}
}
}
/* clear timers etc */
emview_analysis_clear_all(a);
}
a->last_nonce = 0;
a->last_seqno = -1;
gettimeofday(&(a->start_time), NULL);
a->epoch_start_time = a->start_time;
}
void emview_analysis_get_start_time(struct timeval *tv)
{
*tv = _core.analysis.start_time;
}
void emview_analysis_get_sim_time(struct timeval *tv)
{
struct timeval now;
gettimeofday(&now, NULL);
misc_tv_sub(&now, &(_core.analysis.start_time));
*tv = now;
}
void emview_analysis_parse_commands(analysis_info_t *a, char *config_string)
{
/* set up the parse */
parser_state_t *ps = misc_parse_init(config_string, MISC_PARSE_LF_SCHEME);
/* parse all the module declarations */
while (misc_parse_next_kvp(ps) >= 0) {
parser_state_t *ps2 = misc_parse_init(config_string, MISC_PARSE_COLON_SCHEME);
buf_t *rest = buf_new();
emview_module_t *target_module = NULL;
emview_module_inst_t *target_instance = NULL;
/* search for module and device declarations */
while (misc_parse_next_kvp(ps2) >= 0) {
/* parse module token */
if (strcmp(ps2->key, "module") == 0) {
target_module = emvew_module_lookup(ps2->value);
if (target_module == NULL)
elog(LOG_WARNING, "Unknown module %s in global config", ps2->value);
}
/* parse device (instance) token */
else if (strcmp(ps2->key, "dev") == 0) {
if (target_module) {
int created = 0;
/* separate the nickname and the device */
char *ptr;
char *device_path = NULL;
if ((ptr = strpbrk(ps2->value, ","))) {
*ptr = 0;
device_path = ptr+1;
}
target_instance = emview_mod_inst_lookup_or_create(target_module, ps2->value, &created);
/* $$$ARRG DUPLICATION AGAIN! */
/* here's how this ought to work:
* - module=<module>:instance=<instance-name>:path=<optional-path>
* - in processing emrun configs it checks to see if the device is
* initialized and if not initializes it using the optional path
* - in both places, before the device is processed a general init
* is called to do other one-time inits.
* - in both places other callbacks follow and process remaining
* args.
* - device info can reside wholly in the emrun or in both places
*/
/* initially config the module.. */
if (target_module && target_module->opts.config_new_instance) {
if (created) {
target_module->opts.config_new_instance(target_module,
target_instance, device_path, 0);
elog(LOG_DEBUG(0), "config'd device %s,%s", ps->value, device_path);
}
}
else
elog(LOG_WARNING, "Ignoring 'dev' specifier '%s'", ps->value);
}
else
elog(LOG_WARNING, "'dev' token specified in global config, no active module");
}
/* store all else */
else
misc_parse_dump_curr_to_buf(rest, ps2);
}
/* ok, if we got a module and instance, we callback to plugin */
if (target_module && target_module->opts.analysis_config) {
parser_state_t *ps3 = misc_parse_init(rest->buf, MISC_PARSE_COLON_SCHEME);
target_module->opts.analysis_config(target_module, target_instance, 0, ps3);
misc_parse_cleanup(ps3);
}
buf_free(rest);
misc_parse_cleanup(ps2);
}
/* free it */
misc_parse_cleanup(ps);
}
void emview_analysis_runcommands(sim_config_t *cf)
{
int process_it = 0;
analysis_info_t *a = &(_core.analysis);
/* first time or nonce change */
if (cf->nonce != a->last_nonce) {
if (a->last_nonce)
elog(LOG_INFO, "Simulation restart detected!");
emview_analysis_restart(a);
process_it = 1;
}
/* seqno update */
if (cf->index != a->last_seqno)
process_it = 1;
/* ok, run the commands */
if (process_it) {
/* update the seqno */
a->last_seqno++;
gettimeofday(&(a->epoch_start_time), NULL);
if (a->last_seqno != cf->index) {
elog(LOG_WARNING, "Sequence number gap? New seqno %d, last was %d",
cf->index, a->last_seqno-1);
a->last_seqno = cf->index;
}
/* process the commands */
emview_analysis_parse_commands(a, cf->emview_command);
}
}
See more files for this project here