bluesky_time_hires exec_time; /* Time processing started on operation. */
gpointer store_private; /* For use by the storage implementation */
+
+ /* If storage operations should be charged to any particular profile, which
+ * one? */
+ BlueSkyProfile *profile;
};
/* Support for notification lists. These are lists of one-shot functions which
void bluesky_debug_dump(BlueSkyFS *fs);
+/* Request response time tracking. */
+typedef struct BlueSkyProfile {
+ char *description;
+ GList *events;
+} BlueSkyProfile;
+
+BlueSkyProfile *bluesky_profile_new();
+void bluesky_profile_free(BlueSkyProfile *profile);
+void bluesky_profile_add_event(BlueSkyProfile *profile, char *message);
+void bluesky_profile_print(BlueSkyProfile *profile);
+BlueSkyProfile *bluesky_profile_get();
+void bluesky_profile_set(BlueSkyProfile *profile);
+
#ifdef __cplusplus
}
#endif
bluesky_string_unref(raw);
}
+ BlueSkyProfile *profile = bluesky_profile_get();
+ if (profile != NULL)
+ bluesky_profile_add_event(profile, g_strdup_printf("Fetch log entry"));
+
/* At this point all metadata should be available and we need only remap
* the object data. */
log->data = bluesky_log_map_object(log, TRUE);
g_error("Unable to fetch cloudlog entry!");
}
+ if (profile != NULL)
+ bluesky_profile_add_event(profile, g_strdup_printf("Fetch complete"));
g_cond_broadcast(log->cond);
}
async->notifier_count = 0;
async->barrier = NULL;
async->store_private = NULL;
+ async->profile = bluesky_profile_get();
return async;
}
g_thread_pool_push(notifier_thread_pool, nl, NULL);
}
+ if (async->profile) {
+ bluesky_profile_add_event(
+ async->profile,
+ g_strdup_printf("%s for %s complete",
+ async->op == STORE_OP_GET ? "GET"
+ : async->op == STORE_OP_PUT ? "PUT"
+ : async->op == STORE_OP_DELETE ? "DELETE"
+ : async->op == STORE_OP_BARRIER ? "BARRIER" : "???",
+ async->key)
+ );
+ }
+
if (bluesky_verbose) {
g_log("bluesky/store", G_LOG_LEVEL_DEBUG,
"[%p] complete: elapsed = %"PRIi64" ns, latency = %"PRIi64" ns",
// processing was started, if there could be a delay from submission time.
async->exec_time = bluesky_now_hires();
+ if (async->profile) {
+ bluesky_profile_add_event(
+ async->profile,
+ g_strdup_printf("Start %s for %s",
+ async->op == STORE_OP_GET ? "GET"
+ : async->op == STORE_OP_PUT ? "PUT"
+ : async->op == STORE_OP_DELETE ? "DELETE"
+ : async->op == STORE_OP_BARRIER ? "BARRIER" : "???",
+ async->key)
+ );
+ }
+
if (bluesky_verbose) {
g_log("bluesky/store", G_LOG_LEVEL_DEBUG, "[%p] submit: %s %s",
async,
item = (BlueSkyRangesetItem *)g_sequence_get(i);
*length = (item->start + item->length) - *start;
}
+
+/**** Request response-time tracking. ****/
+/* TODO: Locking */
+typedef struct {
+ bluesky_time_hires timestamp;
+ char *message;
+} RTEvent;
+
+BlueSkyProfile *bluesky_profile_new()
+{
+ return g_new0(BlueSkyProfile, 1);
+}
+
+void bluesky_profile_free(BlueSkyProfile *profile)
+{
+ while (profile->events != NULL) {
+ RTEvent *event = (RTEvent *)profile->events->data;
+ g_free(event->message);
+ g_free(event);
+ profile->events = g_list_delete_link(profile->events, profile->events);
+ }
+ g_free(profile->description);
+ g_free(profile);
+}
+
+void bluesky_profile_add_event(BlueSkyProfile *profile, char *message)
+{
+ g_return_if_fail(profile != NULL);
+
+ RTEvent *event = g_new(RTEvent, 1);
+ event->timestamp = bluesky_now_hires();
+ event->message = message;
+ profile->events = g_list_prepend(profile->events, event);
+}
+
+void bluesky_profile_print(BlueSkyProfile *profile)
+{
+ g_return_if_fail(profile != NULL);
+
+ g_print("Event Timeline: %s\n", profile->description);
+ GList *link = g_list_last(profile->events);
+ bluesky_time_hires last_time = 0;
+ while (link != NULL) {
+ RTEvent *event = (RTEvent *)link->data;
+ g_print(" [%"PRIi64" ns]: %s\n",
+ event->timestamp - last_time, event->message);
+ last_time = event->timestamp;
+ link = link->prev;
+ }
+}
+
+static GStaticPrivate per_thread_profile = G_STATIC_PRIVATE_INIT;
+
+BlueSkyProfile *bluesky_profile_get()
+{
+ return (BlueSkyProfile *)g_static_private_get(&per_thread_profile);
+}
+
+void bluesky_profile_set(BlueSkyProfile *profile)
+{
+ g_static_private_set(&per_thread_profile, profile, NULL);
+}
struct cleanup_list *next;
};
+struct BlueSkyProfile;
+
/* Used to track a single outstanding RPC request. Not all of the fields are
* initially filled in, but more are filled in as the request is processed. */
typedef struct {
/* The corresponding connection on which the request was made. */
RPCConnection *connection;
- /* Timining information for generating statistics about response times. */
- int64_t time_start;
+ /* To track the time to complete this request and a timing breakdown. */
+ struct BlueSkyProfile *profile;
/* Transaction ID of the request, in host byte order. */
uint32_t xid;
async_rpc_flush(req->connection);
g_mutex_unlock(req->connection->send_lock);
+ bluesky_profile_free(req->profile);
+
if (req->args != NULL) {
char buf[4];
XDR xdr;
{
bluesky_time_hires time_end;
+ bluesky_profile_add_event(req->profile,
+ g_strdup("Start encoding NFS response"));
+
GString *str = g_string_new("");
XDR xdr_out;
xdr_string_create(&xdr_out, str, XDR_ENCODE);
req->xid, time_end - req->time_start);
#endif
+ bluesky_profile_add_event(req->profile,
+ g_strdup("NFS reply sent"));
+ bluesky_profile_print(req->profile);
+
/* Clean up. */
+ bluesky_profile_free(req->profile);
g_string_free(str, TRUE);
if (req->args != NULL) {
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, RPCRequest *);
-#if 0
+ bluesky_profile_set(req->profile);
+
if (req->req_proc < sizeof(nfs_proc_names) / sizeof(const char *)) {
- printf("Dispatched NFS RPC message type %s\n",
- nfs_proc_names[req->req_proc]);
- } else {
- printf("Dispatched unknown NFS RPC message type %d\n", req->req_proc);
+ bluesky_profile_add_event(
+ req->profile,
+ g_strdup_printf("Dispatching NFS %s request",
+ nfs_proc_names[req->req_proc])
+ );
}
-#endif
switch (req->req_proc) {
case NFSPROC3_NULL:
RPCRequest *req = g_new0(RPCRequest, 1);
req->connection = rpc;
- req->time_start = time_start;
+ req->profile = bluesky_profile_new();
+ bluesky_profile_add_event(req->profile, g_strdup("Receive NFS request"));
req->xid = xid;
if (ntohl(header->prog) != NFS_PROGRAM) {