[Disksim-users] patch: improved (?) interface ...
Michael Meeks
michael.meeks at novell.com
Mon Aug 6 06:01:22 EDT 2007
Hi there,
My requirements for disk-sim, are (perhaps) rather unlike other
people's: treating it as a black-box, I plug a disk model in one end,
and wish to get a set of timing information out of the other end.
Anyhow, I looked at the disksim_interface.[ch] code, and decided
to write a simple new API to cover my use-case at least:
features:
a) callback based => suitable for a shared library.
b) fully opaque types:
+ extremely extensible without ABI issues
+ better self documenting behaviour
c) no implicit state
+ API has no global-variable requirements,
should be thread-safe in future etc.
d) full closure information
+ critical for propagating d) to the caller,
and allow alternate language bindings
e) namespaced: I used 'IDiskSim', suggestions welcome.
In particular I like properties c & d); which should support (I
hope) what I presume is an ongoing movement of the code away from global
state.
[ Unfortunately the mailing list doesn't like my patch as an
attachment, so I append it ;-]
Thanks,
Michael.
diff --git a/disksim-3.0/src/interface.h b/disksim-3.0/src/interface.h
new file mode 100644
index 0000000..717330d
--- /dev/null
+++ b/disksim-3.0/src/interface.h
@@ -0,0 +1,68 @@
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+/*
+ * A cleaner, more extensible and user-friendly interface for DiskSim
+ */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+// time is the time since simulation start in seconds.
+typedef double IDiskSimTime;
+
+/* opaque handles */
+typedef struct _IDiskSim IDiskSim;
+typedef struct _IDiskSimRequest IDiskSimRequest;
+
+/* necessary callbacks */
+typedef void (*IDiskSimCallback) (IDiskSim *ids,
+ void *closure,
+ IDiskSimTime time);
+typedef void (*IDiskSimScheduleCallback) (IDiskSim *ids,
+ IDiskSimCallback callback,
+ void *callback_closure,
+ IDiskSimTime time_to_call,
+ void *closure);
+typedef void (*IDiskSimDeScheduleCallback) (IDiskSim *ids,
+ IDiskSimCallback callback,
+ void *closure);
+typedef void (*IDiskSimDoneIONotify) (IDiskSim *ids,
+ IDiskSimRequest *req,
+ IDiskSimTime time_completed,
+ void *closure);
+
+/* Disk Simulator */
+IDiskSim *idisksim_init (const char *profile_name,
+ IDiskSimScheduleCallback schedule_fn,
+ IDiskSimDeScheduleCallback de_schedule_fn,
+ IDiskSimDoneIONotify notify_fn,
+ void *closure);
+void idisksim_free (IDiskSim *ids);
+
+/* submit a request */
+void idisksim_submit (IDiskSim *ids,
+ IDiskSimRequest *req,
+ IDiskSimTime time);
+/* process I/O at scheduled time */
+void idisksim_iterate (IDiskSim *ids,
+ IDiskSimTime time);
+
+/* I/O Requests */
+
+typedef enum {
+ IDISKSIM_READ = 'r',
+ IDISKSIM_WRITE = 'w'
+} IDiskSimRequestType;
+
+IDiskSimRequest *idisksim_request_new (IDiskSimRequestType type,
+ unsigned int blkno,
+ int bytecount);
+void idisksim_request_free (IDiskSimRequest *req);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* INTERFACE_H */
diff --git a/disksim-3.0/src/interface.c b/disksim-3.0/src/interface.c
new file mode 100644
index 0000000..94a75fd
--- /dev/null
+++ b/disksim-3.0/src/interface.c
@@ -0,0 +1,219 @@
+#include <stdio.h>
+#include "disksim_global.h"
+#include "disksim_ioface.h"
+#include "disksim_iosim.h"
+#include "disksim_disk.h"
+
+#include "interface.h"
+
+// DiskSim time is in milliseconds (MS)
+#define SYSSIMTIME_TO_MS(syssimtime) (syssimtime*1e3)
+#define MS_TO_SYSSIMTIME(curtime) (curtime/1e3)
+
+/*
+ * FIXME - this interface is an idealised API, unfortunately
+ * the disksim implementation is sufficiently lame that it
+ * cannot easily be realised fully.
+ *
+ * FIXME: peel back disksim_interface.c to work out where
+ * the evil truly comes from.
+ */
+static IDiskSim *urgh_global_state;
+#define SET_GLOBAL_DISKSIM(s) disksim = &(s)->disksim;
+
+struct _IDiskSim {
+ IDiskSimScheduleCallback schedule_fn;
+ IDiskSimDeScheduleCallback de_schedule_fn;
+ IDiskSimDoneIONotify notify_fn;
+ void *closure;
+
+ disksim_t disksim;
+};
+
+#define IDISKSIM_OFFSET (((unsigned char *)&((sim_impl_t *) 0)->disksim))
+#define IDISKSIM_FROM_DISKSIM(s) ((IDiskSim *)((unsigned char *)(s) - SIM_IMPL_DISKSIM_OFFSET))
+
+struct _IDiskSimRequest {
+ IDiskSim *ids;
+ IDiskSimRequestType type;
+ unsigned long blkno;
+ int bytecount;
+ int devno;
+};
+
+/* DiskSim is just unbelievable ! */
+static double
+idisksim_get_simtime (IDiskSim *sim)
+{
+ disksim_t *disksim = &sim->disksim;
+ return simtime; /* macro, and also element name */
+}
+
+static void idisksim_io_done_notify (ioreq_event *curr)
+{
+ IDiskSimRequest *req = curr->buf;
+ IDiskSim *ids = req->ids;
+
+ ids->notify_fn (ids, req,
+ MS_TO_SYSSIMTIME (idisksim_get_simtime (ids)),
+ ids->closure);
+}
+
+IDiskSim *
+idisksim_init (const char *profile_name,
+ IDiskSimScheduleCallback schedule_fn,
+ IDiskSimDeScheduleCallback de_schedule_fn,
+ IDiskSimDoneIONotify notify_fn,
+ void *closure)
+{
+ IDiskSim *ids;
+ char *argv[6];
+
+ if (!schedule_fn || !de_schedule_fn || !notify_fn) {
+ fprintf (stderr, "Error - missing callback\n");
+ return NULL;
+ }
+
+ if (!(ids = calloc (1, sizeof (IDiskSim))))
+ return NULL;
+
+ ids->schedule_fn = schedule_fn;
+ ids->de_schedule_fn = de_schedule_fn;
+ ids->notify_fn = notify_fn;
+ ids->closure = closure;
+
+ fprintf (stderr, "idisksim_init '%s'\n", profile_name);
+ disksim_initialize_disksim_structure (&ids->disksim, sizeof (disksim_t));
+
+ argv[0] = "disksim";
+ argv[1] = profile_name;
+ argv[2] = "/dev/null";
+ argv[3] = "external";
+ argv[4] = "0"; // no io trace file
+ argv[5] = "0"; // synthio
+
+ SET_GLOBAL_DISKSIM (ids);
+ disksim_setup_disksim (6, (char **)argv);
+ disksim_set_external_io_done_notify (idisksim_io_done_notify);
+
+ urgh_global_state = ids;
+
+ fprintf (stderr, "idisksim_init done\n");
+
+ return ids;
+}
+
+void
+idisksim_free (IDiskSim *ids)
+{
+ if (ids)
+ free (ids);
+}
+
+IDiskSimRequest *
+idisksim_request_new (IDiskSimRequestType type,
+ unsigned int blkno,
+ int bytecount)
+{
+ IDiskSimRequest *req;
+
+ if (!(req = calloc (1, sizeof (IDiskSimRequest))))
+ return NULL;
+
+ req->type = type;
+ req->devno = 0;
+ req->blkno = blkno;
+ req->bytecount = bytecount;
+
+ return req;
+}
+
+void
+idisksim_request_free (IDiskSimRequest *req)
+{
+ if (req)
+ free (req);
+}
+
+static void
+idisksim_callback (IDiskSim *ids,
+ void *closure,
+ IDiskSimTime time)
+{
+// fprintf (stderr, "idisksim_callback %p %p %g\n", ids, closure, time);
+ idisksim_iterate (ids, time);
+}
+
+void
+idisksim_submit (IDiskSim *ids,
+ IDiskSimRequest *req,
+ IDiskSimTime time)
+{
+ double curtime = SYSSIMTIME_TO_MS (time);
+ ioreq_event *new;
+
+ SET_GLOBAL_DISKSIM (ids);
+
+ new = (ioreq_event *) getfromextraq();
+
+ assert (new != NULL);
+ new->type = IO_REQUEST_ARRIVE;
+ new->time = curtime;
+ new->busno = 0;
+ new->devno = req->devno;
+ new->blkno = req->blkno;
+ new->flags = req->type == IDISKSIM_READ ? READ : WRITE;
+ new->bcount = req->bytecount / 512;
+ new->flags |= TIME_CRITICAL; // non-background ...
+ new->cause = 0;
+ new->opid = 0;
+
+ // closure
+ req->ids = ids;
+ new->buf = req;
+
+ io_map_trace_request (new);
+
+ /* issue it into simulator */
+ if (ids->disksim.intq)
+ ids->de_schedule_fn (ids, idisksim_callback, ids->closure);
+ addtointq ((event *)new);
+
+ idisksim_iterate (ids, time);
+}
+
+void
+idisksim_iterate (IDiskSim *ids,
+ IDiskSimTime time)
+{
+ double curtime = SYSSIMTIME_TO_MS (time);
+
+ /* if we missed an event - error out ... */
+ if (ids->disksim.intq != NULL && (ids->disksim.intq->time + 0.0001) < curtime) {
+ fprintf (stderr, "external time is ahead of disksim time: %f > %f\n",
+ curtime, ids->disksim.intq->time);
+ return;
+ }
+
+ if (ids->disksim.intq != NULL) {
+ if (ids->disksim.intq->time + 0.0001 < idisksim_get_simtime (ids)) {
+ fprintf (stderr, "Error: time out of sync %g vs %g\n",
+ ids->disksim.intq->time + 0.0001,
+ idisksim_get_simtime (ids));
+ ASSERT (ids->disksim.intq->time + 0.0001 >= idisksim_get_simtime (ids));
+ }
+ }
+
+ /* process events until the next event is either in the future, or nonexistent */
+ while ((ids->disksim.intq != NULL)
+ && (ids->disksim.intq->time <= (curtime + 0.0001)))
+ {
+ SET_GLOBAL_DISKSIM (ids);
+ disksim_simulate_event (0 /* count for debugging */);
+ }
+
+ if (disksim->intq)
+ ids->schedule_fn (ids, idisksim_callback, NULL,
+ MS_TO_SYSSIMTIME(disksim->intq->time),
+ ids->closure);
+}
diff --git a/disksim-3.0/src/checklib.c b/disksim-3.0/src/checklib.c
new file mode 100644
index 0000000..802900b
--- /dev/null
+++ b/disksim-3.0/src/checklib.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <malloc.h>
+#include "interface.h"
+
+typedef struct {
+ IDiskSim *ids;
+ double cur_time;
+ unsigned int completed : 1;
+
+ double next_callback_time;
+ IDiskSimCallback callback;
+ void *callback_closure;
+} SimData;
+
+static void
+schedule_callback (IDiskSim *ids,
+ IDiskSimCallback callback,
+ void *callback_closure,
+ IDiskSimTime time_to_call,
+ void *closure)
+{
+ SimData *sim = closure;
+
+ sim->callback = callback;
+ sim->callback_closure = callback_closure;
+ sim->next_callback_time = time_to_call;
+}
+
+static void
+deschedule_callback (IDiskSim *ids,
+ IDiskSimCallback callback,
+ void *closure)
+{
+ SimData *sim = closure;
+
+ sim->next_callback_time = -1.0;
+ sim->callback = NULL;
+ sim->callback_closure = NULL;
+}
+
+static void
+done_io_notify (IDiskSim *ids,
+ IDiskSimRequest *req,
+ IDiskSimTime time_completed,
+ void *closure)
+{
+ SimData *sim = closure;
+
+ sim->completed = 1;
+ sim->cur_time = time_completed;
+}
+
+
+static SimData *
+create_simulation (const char *param_fname)
+{
+ SimData *sim;
+ IDiskSim *ids;
+
+ if (!(sim = calloc (1, sizeof (SimData))))
+ return NULL;
+
+ if (!(ids = idisksim_init (param_fname,
+ schedule_callback,
+ deschedule_callback,
+ done_io_notify,
+ sim))) {
+ free (sim);
+ return NULL;
+ }
+
+ sim->ids = ids;
+ sim->cur_time = 0.0;
+ sim->completed = 0;
+
+ sim->next_callback_time = -1.0;
+ sim->callback = NULL;
+ sim->callback_closure = NULL;
+
+ return sim;
+}
+
+static void
+sim_free (SimData *sim)
+{
+ if (!sim)
+ return;
+ idisksim_free (sim->ids);
+ free (sim);
+}
+
+static void
+sim_callback (SimData *sim)
+{
+ IDiskSimCallback callback = sim->callback;
+ void *closure = sim->callback_closure;
+
+ /* the callback may register another callback
+ so de-register it first */
+ sim->next_callback_time = -1;
+ sim->callback = NULL;
+ sim->callback_closure = NULL;
+
+ callback (sim->ids, closure, sim->cur_time);
+}
+
+int main (int argc, char **argv)
+{
+ int i;
+ SimData *sim;
+
+ /* single arg. is parameter filename */
+ sim = create_simulation (argv[argc-1]);
+
+ for (i = 0; i < 10000; i++) {
+ IDiskSimRequest *req = idisksim_request_new (IDISKSIM_READ, i, 4096);
+
+ idisksim_submit (sim->ids, req, sim->cur_time);
+
+ /* Wait for block to complete */
+ while (sim->next_callback_time >= 0) {
+ /* advance the clock */
+ sim->cur_time = sim->next_callback_time;
+ /* call our callback */
+ sim_callback (sim);
+ }
+
+ idisksim_request_free (req);
+ }
+ fprintf (stderr, "completed in %g seconds\n", sim->cur_time);
+ sim_free (sim);
+
+ return 0;
+}
--
michael.meeks at novell.com <><, Pseudo Engineer, itinerant idiot
More information about the Disksim-users
mailing list