master
commit
69c2b4de29
@ -1 +1 @@
|
||||
Subproject commit 0b9f67d75fd9dab652e1995e7adf91806080523b
|
||||
Subproject commit 726b0804777ef346308f9dfcdf928032c28226a8
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <threads.h>
|
||||
|
||||
extern thread_local uint64_t generic_thread_lock_duration;
|
||||
extern thread_local uint64_t generic_thread_lock_longest;
|
||||
extern thread_local uint64_t generic_thread_start_timestamp;
|
||||
|
||||
void generic_thread_dump_lock_overhead(void);
|
||||
void generic_thread_initialize(void);
|
@ -1,68 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <spinlock/mcs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arch/getcycles.h"
|
||||
#include "runtime.h"
|
||||
#include "generic_thread.h"
|
||||
|
||||
typedef ck_spinlock_mcs_t lock_t;
|
||||
|
||||
/* A linked list of nodes */
|
||||
struct lock_wrapper {
|
||||
uint64_t longest_held;
|
||||
uint64_t total_held;
|
||||
ck_spinlock_mcs_t lock;
|
||||
};
|
||||
|
||||
/* A node on the linked list */
|
||||
struct lock_node {
|
||||
struct ck_spinlock_mcs node;
|
||||
uint64_t time_locked;
|
||||
};
|
||||
|
||||
typedef struct lock_wrapper lock_t;
|
||||
typedef struct lock_node lock_node_t;
|
||||
|
||||
/**
|
||||
* Initializes a lock of type lock_t
|
||||
* Initializes a lock
|
||||
* @param lock - the address of the lock
|
||||
*/
|
||||
#define LOCK_INIT(lock) ck_spinlock_mcs_init((lock))
|
||||
static inline void
|
||||
lock_init(lock_t *self)
|
||||
{
|
||||
self->total_held = 0;
|
||||
self->longest_held = 0;
|
||||
ck_spinlock_mcs_init(&self->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a lock is locked
|
||||
* @param lock - the address of the lock
|
||||
* @returns bool if lock is locked
|
||||
*/
|
||||
|
||||
#define LOCK_IS_LOCKED(lock) ck_spinlock_mcs_locked((lock))
|
||||
static inline bool
|
||||
lock_is_locked(lock_t *self)
|
||||
{
|
||||
return ck_spinlock_mcs_locked(&self->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a lock, keeping track of overhead
|
||||
* @param lock - the address of the lock
|
||||
* @param unique_variable_name - a unique prefix to hygienically namespace an associated lock/unlock pair
|
||||
* @param node - node to add to lock
|
||||
*/
|
||||
static inline void
|
||||
lock_lock(lock_t *self, lock_node_t *node)
|
||||
{
|
||||
assert(node->time_locked == 0);
|
||||
|
||||
#define LOCK_LOCK_WITH_BOOKKEEPING(lock, unique_variable_name) \
|
||||
struct ck_spinlock_mcs _hygiene_##unique_variable_name##_node; \
|
||||
uint64_t _hygiene_##unique_variable_name##_pre = __getcycles(); \
|
||||
ck_spinlock_mcs_lock((lock), &(_hygiene_##unique_variable_name##_node)); \
|
||||
uint64_t _hygiene_##unique_variable_name##_duration = (__getcycles() - _hygiene_##unique_variable_name##_pre); \
|
||||
if (_hygiene_##unique_variable_name##_duration > generic_thread_lock_longest) { \
|
||||
generic_thread_lock_longest = _hygiene_##unique_variable_name##_duration; \
|
||||
} \
|
||||
generic_thread_lock_duration += _hygiene_##unique_variable_name##_duration;
|
||||
node->time_locked = __getcycles();
|
||||
ck_spinlock_mcs_lock(&self->lock, &node->node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks a lock
|
||||
* @param lock - the address of the lock
|
||||
* @param unique_variable_name - a unique prefix to hygienically namespace an associated lock/unlock pair
|
||||
* @param node - node used when calling lock_lock
|
||||
*/
|
||||
#define LOCK_UNLOCK_WITH_BOOKKEEPING(lock, unique_variable_name) \
|
||||
ck_spinlock_mcs_unlock(lock, &(_hygiene_##unique_variable_name##_node));
|
||||
static inline void
|
||||
lock_unlock(lock_t *self, lock_node_t *node)
|
||||
{
|
||||
assert(node->time_locked > 0);
|
||||
|
||||
/**
|
||||
* Locks a lock, keeping track of overhead
|
||||
* Assumes the availability of DEFAULT as a hygienic prefix for DEFAULT_node and DEFAULT_pre
|
||||
*
|
||||
* As such, this API can only be used once in a lexical scope.
|
||||
*
|
||||
* Use LOCK_LOCK_WITH_BOOKKEEPING and LOCK_UNLOCK_WITH_BOOKKEEPING if multiple locks are required
|
||||
* @param lock - the address of the lock
|
||||
*/
|
||||
#define LOCK_LOCK(lock) LOCK_LOCK_WITH_BOOKKEEPING(lock, DEFAULT)
|
||||
|
||||
/**
|
||||
* Unlocks a lock
|
||||
* Uses lock node NODE_DEFAULT and timestamp PRE_DEFAULT, so this assumes use of LOCK_LOCK
|
||||
* This API can only be used once in a lexical scope. If this isn't true, use LOCK_LOCK_WITH_BOOKKEEPING and
|
||||
* LOCK_UNLOCK_WITH_BOOKKEEPING
|
||||
* @param lock - the address of the lock
|
||||
*/
|
||||
#define LOCK_UNLOCK(lock) LOCK_UNLOCK_WITH_BOOKKEEPING(lock, DEFAULT)
|
||||
ck_spinlock_mcs_unlock(&self->lock, &node->node);
|
||||
uint64_t now = __getcycles();
|
||||
assert(node->time_locked < now);
|
||||
uint64_t duration = now - node->time_locked;
|
||||
node->time_locked = 0;
|
||||
if (unlikely(duration > self->longest_held)) { self->longest_held = duration; }
|
||||
self->total_held += duration;
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include "arch/getcycles.h"
|
||||
#include "debuglog.h"
|
||||
|
||||
extern uint32_t runtime_processor_speed_MHz;
|
||||
extern uint32_t runtime_quantum_us;
|
||||
|
||||
/* Implemented by listener and workers */
|
||||
|
||||
thread_local uint64_t generic_thread_lock_duration = 0;
|
||||
thread_local uint64_t generic_thread_lock_longest = 0;
|
||||
thread_local uint64_t generic_thread_start_timestamp = 0;
|
||||
|
||||
void
|
||||
generic_thread_initialize()
|
||||
{
|
||||
generic_thread_start_timestamp = __getcycles();
|
||||
generic_thread_lock_longest = 0;
|
||||
generic_thread_lock_duration = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports lock contention
|
||||
*/
|
||||
void
|
||||
generic_thread_dump_lock_overhead()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
#ifdef LOG_LOCK_OVERHEAD
|
||||
uint64_t duration = __getcycles() - generic_thread_start_timestamp;
|
||||
debuglog("Locks consumed %lu / %lu cycles, or %f%%\n", generic_thread_lock_duration, duration,
|
||||
(double)generic_thread_lock_duration / duration * 100);
|
||||
debuglog("Longest Held Lock was %lu cycles, or %f quantums\n", generic_thread_lock_longest,
|
||||
(double)generic_thread_lock_longest / ((uint64_t)runtime_processor_speed_MHz * runtime_quantum_us));
|
||||
#endif
|
||||
#endif
|
||||
}
|
@ -0,0 +1 @@
|
||||
out.png
|
After Width: | Height: | Size: 606 KiB |
After Width: | Height: | Size: 2.9 MiB |
@ -0,0 +1,20 @@
|
||||
SLEDGE_BINARY_DIR=../../runtime/bin
|
||||
HOSTNAME=localhost
|
||||
|
||||
default: run
|
||||
|
||||
clean:
|
||||
rm -rf res/*
|
||||
|
||||
run:
|
||||
LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} ${SLEDGE_BINARY_DIR}/sledgert spec.json
|
||||
|
||||
debug:
|
||||
SLEDGE_DISABLE_PREEMPTION=true SLEDGE_NWORKERS=1 LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} gdb ${SLEDGE_BINARY_DIR}/sledgert --eval-command="run spec.json"
|
||||
|
||||
valgrind:
|
||||
SLEDGE_DISABLE_PREEMPTION=true SLEDGE_NWORKERS=1 LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} valgrind --leak-check=full --max-stackframe=11150456 --run-libc-freeres=no --run-cxx-freeres=no ${SLEDGE_BINARY_DIR}/sledgert spec.json
|
||||
|
||||
.PHONY: client
|
||||
client:
|
||||
cat ./0_depth.png | http "${HOSTNAME}:10000/depth_to_xyz" > ./out.png
|
After Width: | Height: | Size: 1.5 MiB |
@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"name": "cmu",
|
||||
"port": 10000,
|
||||
"replenishment-period-us": 0,
|
||||
"max-budget-us": 0,
|
||||
"routes": [
|
||||
{
|
||||
"route": "/depth_to_xyz",
|
||||
"path": "depth_to_xyz.wasm.so",
|
||||
"expected-execution-us": 5000,
|
||||
"relative-deadline-us": 360000,
|
||||
"http-resp-size": 5335057,
|
||||
"http-resp-content-type": "img/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Loading…
Reference in new issue