[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