IDE: Optimization of modification events processing in text editors.
Too many modifications types where registered, and then too many events were fired.
Also, in case of uninterrupted sequence of events, updates to the model is deferred to the end of that sequence (wx.Callafter).
/*
* DEBUGGER code
*
* On "publish", when buffer is free, debugger stores arbitrary variables
* content into, and mark this buffer as filled
*
*
* Buffer content is read asynchronously, (from non real time part),
* and then buffer marked free again.
*
*
* */
#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE
void __init_debug (void){}
void __cleanup_debug (void){}
void __retrieve_debug(void){}
void __publish_debug (void){}
#else
#include "iec_types_all.h"
#include "POUS.h"
/*for memcpy*/
#include <string.h>
#include <stdio.h>
typedef unsigned int dbgvardsc_index_t;
typedef unsigned short trace_buf_offset_t;
#define BUFFER_EMPTY 0
#define BUFFER_FULL 1
#ifndef TARGET_ONLINE_DEBUG_DISABLE
#define TRACE_BUFFER_SIZE 4096
#define TRACE_LIST_SIZE 1024
/* Atomically accessed variable for buffer state */
static long trace_buffer_state = BUFFER_EMPTY;
typedef struct trace_item_s {
dbgvardsc_index_t dbgvardsc_index;
} trace_item_t;
trace_item_t trace_list[TRACE_LIST_SIZE];
char trace_buffer[TRACE_BUFFER_SIZE];
/* Trace's cursor*/
static trace_item_t *trace_list_collect_cursor = trace_list;
static trace_item_t *trace_list_addvar_cursor = trace_list;
static const trace_item_t *trace_list_end =
&trace_list[TRACE_LIST_SIZE-1];
static char *trace_buffer_cursor = trace_buffer;
static const char *trace_buffer_end = trace_buffer + TRACE_BUFFER_SIZE;
#define FORCE_BUFFER_SIZE 1024
#define FORCE_LIST_SIZE 256
typedef struct force_item_s {
dbgvardsc_index_t dbgvardsc_index;
void *value_pointer_backup;
} force_item_t;
force_item_t force_list[FORCE_LIST_SIZE];
char force_buffer[FORCE_BUFFER_SIZE];
/* Force's cursor*/
static force_item_t *force_list_apply_cursor = force_list;
static force_item_t *force_list_addvar_cursor = force_list;
static const force_item_t *force_list_end =
&force_list[FORCE_LIST_SIZE-1];
static char *force_buffer_cursor = force_buffer;
static const char *force_buffer_end = force_buffer + FORCE_BUFFER_SIZE;
#endif
/***
* Declare programs
**/
%(programs_declarations)s
/***
* Declare global variables from resources and conf
**/
%(extern_variables_declarations)s
typedef const struct {
void *ptr;
__IEC_types_enum type;
} dbgvardsc_t;
static const dbgvardsc_t dbgvardsc[] = {
%(variable_decl_array)s
};
static const dbgvardsc_index_t retain_list[] = {
%(retain_vardsc_index_array)s
};
static unsigned int retain_list_collect_cursor = 0;
static const unsigned int retain_list_size = sizeof(retain_list)/sizeof(dbgvardsc_index_t);
typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*);
void __for_each_variable_do(__for_each_variable_do_fp fp)
{
unsigned int i;
for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){
dbgvardsc_t *dsc = &dbgvardsc[i];
if(dsc->type != UNKNOWN_ENUM)
(*fp)(dsc);
}
}
#define __Unpack_desc_type dbgvardsc_t
%(var_access_code)s
void Remind(unsigned int offset, unsigned int count, void * p);
extern int CheckRetainBuffer(void);
extern void InitRetain(void);
void __init_debug(void)
{
/* init local static vars */
#ifndef TARGET_ONLINE_DEBUG_DISABLE
trace_buffer_cursor = trace_buffer;
trace_list_addvar_cursor = trace_list;
trace_list_collect_cursor = trace_list;
trace_buffer_state = BUFFER_EMPTY;
force_buffer_cursor = force_buffer;
force_list_addvar_cursor = force_list;
force_list_apply_cursor = force_list;
#endif
InitRetain();
/* Iterate over all variables to fill debug buffer */
if(CheckRetainBuffer()){
unsigned int retain_offset = 0;
retain_list_collect_cursor = 0;
/* iterate over retain list */
while(retain_list_collect_cursor < retain_list_size){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
retain_list[retain_list_collect_cursor]];
UnpackVar(dsc, &value_p, NULL, &size);
/* if buffer not full */
Remind(retain_offset, size, value_p);
/* increment cursor according size*/
retain_offset += size;
retain_list_collect_cursor++;
}
}else{
char mstr[] = "RETAIN memory invalid - defaults used";
LogMessage(LOG_WARNING, mstr, sizeof(mstr));
}
}
extern void InitiateDebugTransfer(void);
extern void CleanupRetain(void);
extern unsigned long __tick;
void __cleanup_debug(void)
{
#ifndef TARGET_ONLINE_DEBUG_DISABLE
trace_buffer_cursor = trace_buffer;
InitiateDebugTransfer();
#endif
CleanupRetain();
}
void __retrieve_debug(void)
{
}
void Retain(unsigned int offset, unsigned int count, void * p);
/* Return size of all retain variables */
unsigned int GetRetainSize(void)
{
unsigned int retain_size = 0;
retain_list_collect_cursor = 0;
/* iterate over retain list */
while(retain_list_collect_cursor < retain_list_size){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
retain_list[retain_list_collect_cursor]];
UnpackVar(dsc, &value_p, NULL, &size);
retain_size += size;
retain_list_collect_cursor++;
}
return retain_size;
}
extern void PLC_GetTime(IEC_TIME*);
extern int TryEnterDebugSection(void);
extern long AtomicCompareExchange(long*, long, long);
extern long long AtomicCompareExchange64(long long* , long long , long long);
extern void LeaveDebugSection(void);
extern void ValidateRetainBuffer(void);
extern void InValidateRetainBuffer(void);
#define __ReForceOutput_case_p(TYPENAME) \
case TYPENAME##_P_ENUM : \
case TYPENAME##_O_ENUM : \
{ \
char *next_cursor = force_buffer_cursor + sizeof(TYPENAME); \
if(next_cursor <= force_buffer_end ){ \
/* outputs real value must be systematically forced */ \
if(vartype == TYPENAME##_O_ENUM) \
/* overwrite value pointed by backup */ \
*((TYPENAME *)force_list_apply_cursor->value_pointer_backup) = \
*((TYPENAME *)force_buffer_cursor); \
/* inc force_buffer cursor */ \
force_buffer_cursor = next_cursor; \
}else{ \
stop = 1; \
} \
} \
break;
void __publish_debug(void)
{
InValidateRetainBuffer();
#ifndef TARGET_ONLINE_DEBUG_DISABLE
/* Check there is no running debugger re-configuration */
if(TryEnterDebugSection()){
/* Lock buffer */
long latest_state = AtomicCompareExchange(
&trace_buffer_state,
BUFFER_EMPTY,
BUFFER_FULL);
/* If buffer was free */
if(latest_state == BUFFER_EMPTY)
{
int stop = 0;
/* Reset force list cursor */
force_list_apply_cursor = force_list;
/* iterate over force list */
while(!stop && force_list_apply_cursor < force_list_addvar_cursor){
dbgvardsc_t *dsc = &dbgvardsc[
force_list_apply_cursor->dbgvardsc_index];
void *varp = dsc->ptr;
__IEC_types_enum vartype = dsc->type;
switch(vartype){
__ANY(__ReForceOutput_case_p)
default:
break;
}
force_list_apply_cursor++; \
}
/* Reset buffer cursor */
trace_buffer_cursor = trace_buffer;
/* Reset trace list cursor */
trace_list_collect_cursor = trace_list;
/* iterate over trace list */
while(trace_list_collect_cursor < trace_list_addvar_cursor){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
trace_list_collect_cursor->dbgvardsc_index];
UnpackVar(dsc, &value_p, NULL, &size);
/* copy visible variable to buffer */;
if(__Is_a_string(dsc)){
/* optimization for strings */
/* assume NULL terminated strings */
size = ((STRING*)value_p)->len + 1;
}
/* compute next cursor positon.*/
next_cursor = trace_buffer_cursor + size;
/* check for buffer overflow */
if(next_cursor < trace_buffer_end)
/* copy data to the buffer */
memcpy(trace_buffer_cursor, value_p, size);
else
/* stop looping in case of overflow */
break;
/* increment cursor according size*/
trace_buffer_cursor = next_cursor;
trace_list_collect_cursor++;
}
/* Leave debug section,
* Trigger asynchronous transmission
* (returns immediately) */
InitiateDebugTransfer(); /* size */
}
LeaveDebugSection();
}
#endif
unsigned int retain_offset = 0;
/* when not debugging, do only retain */
retain_list_collect_cursor = 0;
/* iterate over retain list */
while(retain_list_collect_cursor < retain_list_size){
void *value_p = NULL;
size_t size;
char* next_cursor;
dbgvardsc_t *dsc = &dbgvardsc[
retain_list[retain_list_collect_cursor]];
UnpackVar(dsc, &value_p, NULL, &size);
/* if buffer not full */
Retain(retain_offset, size, value_p);
/* increment cursor according size*/
retain_offset += size;
retain_list_collect_cursor++;
}
ValidateRetainBuffer();
}
#ifndef TARGET_ONLINE_DEBUG_DISABLE
#define TRACE_LIST_OVERFLOW 1
#define FORCE_LIST_OVERFLOW 2
#define FORCE_BUFFER_OVERFLOW 3
#define __ForceVariable_case_t(TYPENAME) \
case TYPENAME##_ENUM : \
/* add to force_list*/ \
force_list_addvar_cursor->dbgvardsc_index = idx; \
((__IEC_##TYPENAME##_t *)varp)->flags |= __IEC_FORCE_FLAG; \
((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force); \
break;
#define __ForceVariable_case_p(TYPENAME) \
case TYPENAME##_P_ENUM : \
case TYPENAME##_O_ENUM : \
{ \
char *next_cursor = force_buffer_cursor + sizeof(TYPENAME); \
if(next_cursor <= force_buffer_end ){ \
/* add to force_list*/ \
force_list_addvar_cursor->dbgvardsc_index = idx; \
/* save pointer to backup */ \
force_list_addvar_cursor->value_pointer_backup = \
((__IEC_##TYPENAME##_p *)varp)->value; \
/* store forced value in force_buffer */ \
*((TYPENAME *)force_buffer_cursor) = *((TYPENAME *)force); \
/* replace pointer with pointer to force_buffer */ \
((__IEC_##TYPENAME##_p *)varp)->value = \
(TYPENAME *)force_buffer_cursor; \
/* mark variable as forced */ \
((__IEC_##TYPENAME##_p *)varp)->flags |= __IEC_FORCE_FLAG; \
/* inc force_buffer cursor */ \
force_buffer_cursor = next_cursor; \
/* outputs real value must be systematically forced */ \
if(vartype == TYPENAME##_O_ENUM) \
*(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\
} else { \
error_code = FORCE_BUFFER_OVERFLOW; \
goto error_cleanup; \
} \
} \
break;
void ResetDebugVariables(void);
int RegisterDebugVariable(dbgvardsc_index_t idx, void* force)
{
int error_code = 0;
if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){
/* add to trace_list, inc trace_list_addvar_cursor*/
if(trace_list_addvar_cursor <= trace_list_end){
trace_list_addvar_cursor->dbgvardsc_index = idx;
trace_list_addvar_cursor++;
} else {
error_code = TRACE_LIST_OVERFLOW;
goto error_cleanup;
}
if(force){
if(force_list_addvar_cursor <= force_list_end){
dbgvardsc_t *dsc = &dbgvardsc[idx];
void *varp = dsc->ptr;
__IEC_types_enum vartype = dsc->type;
switch(vartype){
__ANY(__ForceVariable_case_t)
__ANY(__ForceVariable_case_p)
default:
break;
}
/* inc force_list cursor */
force_list_addvar_cursor++;
} else {
error_code = FORCE_LIST_OVERFLOW;
goto error_cleanup;
}
}
}
return 0;
error_cleanup:
ResetDebugVariables();
trace_buffer_state = BUFFER_EMPTY;
return error_code;
}
#define ResetForcedVariable_case_t(TYPENAME) \
case TYPENAME##_ENUM : \
((__IEC_##TYPENAME##_t *)varp)->flags &= ~__IEC_FORCE_FLAG; \
/* for local variable we don't restore original value */ \
/* that can be added if needed, but it was like that since ever */ \
break;
#define ResetForcedVariable_case_p(TYPENAME) \
case TYPENAME##_P_ENUM : \
case TYPENAME##_O_ENUM : \
((__IEC_##TYPENAME##_p *)varp)->flags &= ~__IEC_FORCE_FLAG; \
/* restore backup to pointer */ \
((__IEC_##TYPENAME##_p *)varp)->value = \
force_list_apply_cursor->value_pointer_backup; \
break;
void ResetDebugVariables(void)
{
/* Reset trace list */
trace_list_addvar_cursor = trace_list;
force_list_apply_cursor = force_list;
/* Restore forced variables */
while(force_list_apply_cursor < force_list_addvar_cursor){
dbgvardsc_t *dsc = &dbgvardsc[
force_list_apply_cursor->dbgvardsc_index];
void *varp = dsc->ptr;
switch(dsc->type){
__ANY(ResetForcedVariable_case_t)
__ANY(ResetForcedVariable_case_p)
default:
break;
}
/* inc force_list cursor */
force_list_apply_cursor++;
} /* else TODO: warn user about failure to force */
/* Reset force list */
force_list_addvar_cursor = force_list;
/* Reset force buffer */
force_buffer_cursor = force_buffer;
}
void FreeDebugData(void)
{
/* atomically mark buffer as free */
AtomicCompareExchange(
&trace_buffer_state,
BUFFER_FULL,
BUFFER_EMPTY);
}
int WaitDebugData(unsigned long *tick);
/* Wait until debug data ready and return pointer to it */
int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){
int wait_error = WaitDebugData(tick);
if(!wait_error){
*size = trace_buffer_cursor - trace_buffer;
*buffer = trace_buffer;
}
return wait_error;
}
#endif
#endif