1
0
Fork 0
fgdata/Nasal/frame_utils.nas
Richard Harrison bcd59f8370 Nasal PartitionProcessor added time limiter
the partition processor can now either process a certain number of items per frame, or spend a certain amount of time processing items.

The two options work together - so typically you'd pick a sensible amount of items to process per frame and then maybe also set a maximum amount of time per frame to be sure.

Using the time limit option will take slightly more CPU - but can still be a net benefit
2020-10-25 20:02:41 +01:00

152 lines
5.9 KiB
Text

#---------------------------------------------------------------------------
#
# Title : Frame Utils
#
# File Type : Implementation File
#
# Description : Objects related to frame processing
#
# Author : Richard Harrison (richard@zaretto.com)
#
# Creation Date : 05-05-2019
#
# Version : 1.0
#
# Copyright (C) 2019 Richard Harrison Released under GPL V2
#
#---------------------------------------------------------------------------*/
#---------------------------------------------------------------------------*/
# Partition data and process
#
# This manages the processing of data in a manner suitable for real time
# operations. Given a data array [0..size] this will process a number
# of array elements each time it is called This allows for a simple way
# to split up intensive processing across multiple frames.
#
# The limit is the number of elements to process per invocation or
# a specific amount of time.
#
# To limit the amount of time requires a timestamp object to be set using
# the set_timestamp method and then to set the maximum amount of
# time (in microseconds) by calling set_max_time_usec. A value of 500us is
# a good value to use - but it is upto the implementor to choose a value that
# is suited to their environment
#
# Usually one of more instances of this class will be contained within
# another object, however this will work equally well in global space.
#
# example usage (object);
#
# var VSD_Device =
# {
# new : func(designation, model_element, target_module_id, root_node)
# {
# ...
# obj.process_targets = PartitionProcessor.new("VSD-targets", 20, nil);
# obj.process_targets.set_max_time_usec(500);
# ...
# me.process_targets.set_timestamp(notification.Timestamp);
#
# then invoke.
# me.process_targets.process(me, awg_9.tgts_list,
# func(pp, obj, data){
# # initialisation; called before processing element[0]
# # params
# # pp is the partition processor that called this
# # obj is the reference object (first argument in the .process)
# # data is the entire data array.
# }
# ,
# func(pp, obj, element){
# # proces individual element;
# # params
# # pp is the partition processor that called this
# # obj is the reference object (first argument in the .process)
# # element is the element data[pp.data_index]
# # return 0 to stop processing any more elements and call the completed method
# # return 1 to continue processing.
# },
# func(pp, obj, data)
# {
# # completed; called after the last element processed
# # params
# # pp is the partition processor that called this
# # obj is the reference object (first argument in the .process)
# # data is the entire data array.
# });
var PartitionProcessor =
{
debug_output : 0,
new : func(_name, _size, _timestamp=nil){
var obj = {
parents : [PartitionProcessor],
data_index : 0,
ppos : 0,
name : _name,
end : 0,
partition_size : _size,
timestamp : _timestamp,
max_time_usec : 0,
};
return obj;
},
set_max_time_usec : func(_maxTimeUsec){
me.max_time_usec = _maxTimeUsec;
},
set_timestamp : func(_timestamp){
me.timestamp = _timestamp;
},
process : func (object, data, init_method, process_method, complete_method){
if (me.end != size(data)) {
# data changed during processing restart at the beginning.
me.data_index = 0;
}
if (me.data_index == 0) {
me.end = size(data);
init_method(me, object, data);
}
if (me.end == 0)
return;
me.start_pos = me.data_index;
if (me.timestamp != nil and me.max_time_usec > 0) {
me.start_time = me.timestamp.elapsedUSec();
me.end_time = me.start_time + me.max_time_usec;
} else {
me.start_time = 0;
me.end_time = 0;
}
for (me.ppos=0;me.ppos < me.partition_size; me.ppos += 1) {
if (me.data_index >= me.end) {
complete_method(me, object, data);
me.data_index = 0;
return;
}
if (!process_method(me, object, data[me.data_index])) {
complete_method(me, object, data);
me.data_index = 0;
return; # halt processing requested.
} else
me.data_index += 1;
if (me.data_index == me.start_pos) {
complete_method(me, object, data);
return;
}
if (me.end_time > 0 and me.timestamp.elapsedUSec() > me.end_time) {
if (PartitionProcessor.debug_output)
printf("PartitionProcessor: [%s] out of time %dus (processed# %d)",me.name, me.timestamp.elapsedUSec() - me.start_time, me.ppos);
return;
}
}
},
};