From: "pi-cheng.chen" pi-cheng.chen@linaro.org
Add 2 new kind of event for running a memory or a io bounded load. "mem" name for a load is memory bounded, and "iorun" name for a load is io bounded. The default file to be written to create the load is /dev/null and the device/file could be specified with "io_device" key in "global" section. The size of per-thread memory buffer to create IO/memory load could also be specified with "mem_buffer_size" in the same section.
Signed-off-by: Pi-Cheng Chen pi-cheng.chen@linaro.org --- changes from v3: - add example json file to illustrate the usage of the new events - add documentation entries in doc/tutorial.txt for the new events
changes from v2: - allocate / open resouces at parsing stage
changes from v1: - Allocate per-thread memory buffer - Add "mem_buffer_size" in global section to specify the size of buffer - fix possible buffer overrun when creating IO-bounded load --- doc/examples/tutorial/example6.json | 29 +++++++++++++++++++ doc/tutorial.txt | 18 ++++++++++++ src/rt-app.c | 48 ++++++++++++++++++++++++++++++ src/rt-app_parse_config.c | 58 +++++++++++++++++++++++++++++++++++++ src/rt-app_types.h | 16 ++++++++++ 5 files changed, 169 insertions(+) create mode 100644 doc/examples/tutorial/example6.json
diff --git a/doc/examples/tutorial/example6.json b/doc/examples/tutorial/example6.json new file mode 100644 index 0000000..06899eb --- /dev/null +++ b/doc/examples/tutorial/example6.json @@ -0,0 +1,29 @@ +{ + /* + * Simple use case which creates CPU-, memory-, + * and IO-bouned load for 2 seconds duration. + */ + "tasks" : { + "thread0" : { + "instance" : 1, + "loop" : -1, + "run" : 1000, + "mem" : 1000, + "sleep" : 5000, + "iorun" : 100000 + } + }, + "global" : { + "duration" : 2, + "calibration" : "CPU0", + "default_policy" : "SCHED_OTHER", + "pi_enabled" : false, + "lock_pages" : false, + "logdir" : "./", + "log_basename" : "rt-app2", + "ftrace" : true, + "gnuplot" : true, + "io_device" : "/dev/null", + "mem_buffer_size" : 1048576 + } +} diff --git a/doc/tutorial.txt b/doc/tutorial.txt index 12aba47..2eefdb8 100644 --- a/doc/tutorial.txt +++ b/doc/tutorial.txt @@ -67,6 +67,14 @@ case. Default value is False. * gnuplot : Boolean. if True, it will create a gnu plot compatible file for each threads (see gnuplot section for more details). Default value is False.
+"io_device" : Text. Path to the file which will be written to create IO-bounded +busy loop. Specify it carefully since it might damage the specified file. +Default value is "/dev/null". + +"mem_buffer_size" : Integer. The size of per-thread memory buffer in byte being +used to create IO-bounded and memory-bounded busy loop. Default value is +4194304(4MB). + *** default global object: "global" : { "duration" : -1, @@ -78,6 +86,8 @@ each threads (see gnuplot section for more details). Default value is False. "log_basename" : "rt-app", "ftrace" : false, "gnuplot" : false, + "io_device" : "/dev/null" + "mem_buffer_size" : 4194304 }
**** tasks object **** @@ -172,6 +182,14 @@ frequency or the compute capacity of the CPU. * sleep : Integer. Emulate the sleep of a task. The duration is defined in usec.
+* mem : Integer. Emulate the memory write operation. The value defines the size +in byte to be written into the memory buffer. The size of the memory buffer is +defined by "mem_buffer_size" in "global" object. + +* iorun : Integer. Emulate the IO write operation. The value defined the size +in byte to be write into the IO device specified by "io_device" in "global" +object. + * timer : Object. Emulate the wake up of the thread by a timer. Timer differs from sleep event by the start time of the timer duration. Sleep duration starts at the beginning of the sleep event whereas timer duration starts at the end of diff --git a/src/rt-app.c b/src/rt-app.c index 37e9892..4e78844 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -179,6 +179,42 @@ static inline loadwait(unsigned long exec) return load_count; }
+static void ioload(unsigned long count, struct _rtapp_iomem_buf *iomem, int io_fd) +{ + ssize_t ret; + + while (count != 0) { + unsigned long size; + + if (count > iomem->size) + size = iomem->size; + else + size = count; + + ret = write(io_fd, iomem->ptr, size); + if (ret == -1) { + perror("write"); + return; + } + count -= ret; + } +} + +static void memload(unsigned long count, struct _rtapp_iomem_buf *iomem) +{ + while (count > 0) { + unsigned long size; + + if (count > iomem->size) + size = iomem->size; + else + size = count; + + memset(iomem->ptr, 0, size); + count -= size; + } +} + static int run_event(event_data_t *event, int dry_run, unsigned long *perf, unsigned long *duration, rtapp_resource_t *resources) { @@ -271,6 +307,18 @@ static int run_event(event_data_t *event, int dry_run, pthread_mutex_unlock(&(ddata->res.mtx.obj)); break; } + case rtapp_mem: + { + log_debug("mem %d", event->count); + memload(event->count, &rdata->res.buf); + } + break; + case rtapp_iorun: + { + log_debug("iorun %d", event->count); + ioload(event->count, &rdata->res.buf, ddata->res.dev.fd); + } + break; }
return lock; diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 96e5517..def3070 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define PIN2 PIN" " #define PIN3 PIN2" " #define JSON_FILE_BUF_SIZE 4096 +#define DEFAULT_MEM_BUF_SIZE (4 * 1024 * 1024)
/* redefine foreach as in <json/json_object.h> but to be ANSI * compatible */ @@ -191,6 +192,21 @@ static int init_cond_resource(rtapp_resource_t *data, const rtapp_options_t *opt &data->res.cond.attr); }
+static int init_membuf_resource(rtapp_resource_t *data, const rtapp_options_t *opts) +{ + log_info(PIN3 "Init: %s membuf", data->name); + + data->res.buf.ptr = malloc(opts->mem_buffer_size); + data->res.buf.size = opts->mem_buffer_size; +} + +static int init_iodev_resource(rtapp_resource_t *data, const rtapp_options_t *opts) +{ + log_info(PIN3 "Init: %s io device", data->name); + + data->res.dev.fd = open(opts->io_device, O_CREAT | O_WRONLY, 0644); +} + static void init_resource_data(const char *name, int type, int idx, const rtapp_options_t *opts) { @@ -211,6 +227,12 @@ init_resource_data(const char *name, int type, int idx, const rtapp_options_t *o case rtapp_wait: init_cond_resource(data, opts); break; + case rtapp_mem: + init_membuf_resource(data, opts); + break; + case rtapp_iorun: + init_iodev_resource(data, opts); + break; } }
@@ -332,6 +354,32 @@ parse_thread_event_data(char *name, struct json_object *obj, return; }
+ if (!strncmp(name, "mem", strlen("mem")) || + !strncmp(name, "iorun", strlen("iorun"))) { + if (!json_object_is_type(obj, json_type_int)) + goto unknown_event; + + /* create an unique name for per-thread buffer */ + ref = create_unique_name(unique_name, sizeof(unique_name), "mem", tag); + i = get_resource_index(ref, rtapp_mem, opts); + data->res = i; + data->count = json_object_get_int(obj); + + /* A single IO devices for all threads */ + if (strncmp(name, "iorun", strlen("iorun")) == 0) { + i = get_resource_index("io_device", rtapp_iorun, opts); + data->dep = i; + }; + + if (!strncmp(name, "mem", strlen("mem"))) + data->type = rtapp_mem; + else + data->type = rtapp_iorun; + + log_info(PIN2 "type %d count %d", data->type, data->count); + return; + } + if (!strncmp(name, "lock", strlen("lock")) || !strncmp(name, "unlock", strlen("unlock"))) {
@@ -526,6 +574,10 @@ obj_is_event(char *name) return rtapp_suspend; if (!strncmp(name, "resume", strlen("resume"))) return rtapp_resume; + if (!strncmp(name, "mem", strlen("mem"))) + return rtapp_mem; + if (!strncmp(name, "iorun", strlen("iorun"))) + return rtapp_iorun;
return 0; } @@ -710,6 +762,8 @@ parse_global(struct json_object *global, rtapp_options_t *opts) opts->logbasename = strdup("rt-app"); opts->ftrace = 0; opts->pi_enabled = 0; + opts->io_device = strdup("/dev/null"); + opts->mem_buffer_size = DEFAULT_MEM_BUF_SIZE; return; }
@@ -762,6 +816,10 @@ parse_global(struct json_object *global, rtapp_options_t *opts) TRUE, "rt-app"); opts->ftrace = get_bool_value_from(global, "ftrace", TRUE, 0); opts->pi_enabled = get_bool_value_from(global, "pi_enabled", TRUE, 0); + opts->io_device = get_string_value_from(global, "io_device", TRUE, + "/dev/null"); + opts->mem_buffer_size = get_int_value_from(global, "mem_buffer_size", + TRUE, DEFAULT_MEM_BUF_SIZE);
}
diff --git a/src/rt-app_types.h b/src/rt-app_types.h index 1075f64..aab96a7 100644 --- a/src/rt-app_types.h +++ b/src/rt-app_types.h @@ -65,6 +65,8 @@ typedef enum resource_t rtapp_timer, rtapp_suspend, rtapp_resume, + rtapp_mem, + rtapp_iorun, } resource_t;
struct _rtapp_mutex { @@ -86,6 +88,15 @@ struct _rtapp_timer { int init; };
+struct _rtapp_iomem_buf { + char *ptr; + int size; +}; + +struct _rtapp_iodev { + int fd; +}; + /* Shared resources */ typedef struct _rtapp_resource_t { union { @@ -93,6 +104,8 @@ typedef struct _rtapp_resource_t { struct _rtapp_cond cond; struct _rtapp_signal signal; struct _rtapp_timer timer; + struct _rtapp_iomem_buf buf; + struct _rtapp_iodev dev; } res; int index; resource_t type; @@ -104,6 +117,7 @@ typedef struct _event_data_t { int res; int dep; int duration; + int count; } event_data_t;
typedef struct _phase_data_t { @@ -166,6 +180,8 @@ typedef struct _rtapp_options_t {
int ftrace; int die_on_dmiss; + int mem_buffer_size; + char *io_device; } rtapp_options_t;
typedef struct _timing_point_t {