Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions for external memory management of scratch and stream objects #109

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/dispatcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,19 @@ CREATE_DISPATCH(hs_error_t, hs_free_database, hs_database_t *db);
CREATE_DISPATCH(hs_error_t, hs_open_stream, const hs_database_t *db,
unsigned int flags, hs_stream_t **stream);

CREATE_DISPATCH(hs_error_t, hs_open_stream_at, const hs_database_t *db,
unsigned int flags, hs_stream_t *stream);

CREATE_DISPATCH(hs_error_t, hs_scan_stream, hs_stream_t *id, const char *data,
unsigned int length, unsigned int flags, hs_scratch_t *scratch,
match_event_handler onEvent, void *ctxt);

CREATE_DISPATCH(hs_error_t, hs_close_stream, hs_stream_t *id,
hs_scratch_t *scratch, match_event_handler onEvent, void *ctxt);

CREATE_DISPATCH(hs_error_t, hs_close_stream_nofree, hs_stream_t *id,
hs_scratch_t *scratch, match_event_handler onEvent, void *ctxt);

CREATE_DISPATCH(hs_error_t, hs_scan_vector, const hs_database_t *db,
const char *const *data, const unsigned int *length,
unsigned int count, unsigned int flags, hs_scratch_t *scratch,
Expand Down
100 changes: 100 additions & 0 deletions src/hs_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,41 @@ typedef int (HS_CDECL *match_event_handler)(unsigned int id,
hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db, unsigned int flags,
hs_stream_t **stream);

/**
* Open and initialise a stream from pre-allocated memory.
*
* @param db
* A compiled pattern database.
*
* @param flags
* Flags modifying the behaviour of the stream. This parameter is provided
* for future use and is unused at present.
*
* @param stream
* The caller sets stream to point at a block of memory at least the size
* returned by hs_stream_size().
*
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
hs_error_t HS_CDECL hs_open_stream_at(const hs_database_t *db, unsigned int flags,
hs_stream_t *stream);

/**
* Report the size of a stream object based on the given database.
*
* @param db
* A compiled pattern database.
*
* @param streams_size
* Returns the size in bytes of the given stream.
*
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
hs_error_t HS_CDECL hs_stream_size(const hs_database_t *db,
size_t *stream_size);

/**
* Write data to be scanned to the opened stream.
*
Expand Down Expand Up @@ -232,6 +267,31 @@ hs_error_t HS_CDECL hs_scan_stream(hs_stream_t *id, const char *data,
hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
match_event_handler onEvent, void *ctxt);

/**
* Close a stream, but do not free the memory associated with the stream id.
* This must be called when the stream is externally allocated.
*
* @param id
* The stream ID returned by @ref hs_open_stream().
*
* @param scratch
* A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is
* allowed to be NULL only if the @p onEvent callback is also NULL.
*
* @param onEvent
* Pointer to a match event callback function. If a NULL pointer is given,
* no matches will be returned.
*
* @param ctxt
* The user defined pointer which will be passed to the callback function
* when a match occurs.
*
* @return
* Returns @ref HS_SUCCESS on success, other values on failure.
*/
hs_error_t HS_CDECL hs_close_stream_nofree(hs_stream_t *id, hs_scratch_t *scratch,
match_event_handler onEvent, void *ctxt);

/**
* Reset a stream to an initial state.
*
Expand Down Expand Up @@ -576,6 +636,29 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
hs_scratch_t **dest);

/**
* Place a scratch space at the specified address and initialize it as
* a clone of an existing scratch space.
*
* This is useful when multiple concurrent threads will be using the same set
* of compiled databases, and another scratch space is required. The caller
* must allocate a block of memory the size as specified by hs_scratch_size(src).
*
* @param src
* The existing @ref hs_scratch_t to be cloned.
*
* @param dest
* The caller sets dest to the start of the allocated block of memory.
* Upon return dest is set to the aligned scratch space. Please note that
* dest->scratch_alloc points to the original base of the block of memory.
*
* @return
* @ref HS_SUCCESS on success; @ref HS_NOMEM if the allocation fails.
* Other errors may be returned if invalid parameters are specified.
*/
hs_error_t HS_CDECL hs_clone_scratch_at(const hs_scratch_t *src,
hs_scratch_t **dest);

/**
* Provides the size of the given scratch space.
*
Expand All @@ -593,6 +676,23 @@ hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch,
size_t *scratch_size);

/**
* Provides the base address of the scratch area, which can be used for freeing
* externally allocated scratch buffers.
*
* @param scratch
* A per-thread scratch space allocated by @ref hs_alloc_scratch() or @ref
* hs_clone_scratch().
*
* @param memaddr
* On success, the pointer to the base of the allocated memory of the
* scratch area.
*
* @return
* @ref HS_SUCCESS on success, other values on failure.
*/
hs_error_t HS_CDECL hs_scratch_memaddr(const hs_scratch_t *scratch, char **memaddr);

/**
* Free a scratch block previously allocated by @ref hs_alloc_scratch() or @ref
* hs_clone_scratch().
Expand Down
50 changes: 50 additions & 0 deletions src/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,34 @@ hs_error_t HS_CDECL hs_open_stream(const hs_database_t *db,
}


HS_PUBLIC_API
hs_error_t HS_CDECL hs_open_stream_at(const hs_database_t *db,
UNUSED unsigned flags,
hs_stream_t *stream) {
if (unlikely(!stream)) {
return HS_INVALID;
}

hs_error_t err = validDatabase(db);
if (unlikely(err != HS_SUCCESS)) {
return err;
}

const struct RoseEngine *rose = hs_get_bytecode(db);
if (unlikely(!ISALIGNED_16(rose))) {
return HS_INVALID;
}

if (unlikely(rose->mode != HS_MODE_STREAM)) {
return HS_DB_MODE_ERROR;
}

init_stream(stream, rose, 1);

return HS_SUCCESS;
}


static really_inline
void rawEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
const struct RoseEngine *rose = id->rose;
Expand Down Expand Up @@ -999,6 +1027,28 @@ hs_error_t HS_CDECL hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch,
return HS_SUCCESS;
}

HS_PUBLIC_API
hs_error_t HS_CDECL hs_close_stream_nofree(hs_stream_t *id, hs_scratch_t *scratch,
match_event_handler onEvent,
void *context) {
if (!id) {
return HS_INVALID;
}

if (onEvent) {
if (!scratch || !validScratch(id->rose, scratch)) {
return HS_INVALID;
}
if (unlikely(markScratchInUse(scratch))) {
return HS_SCRATCH_IN_USE;
}
report_eod_matches(id, scratch, onEvent, context);
unmarkScratchInUse(scratch);
}

return HS_SUCCESS;
}

HS_PUBLIC_API
hs_error_t HS_CDECL hs_reset_stream(hs_stream_t *id, UNUSED unsigned int flags,
hs_scratch_t *scratch,
Expand Down
67 changes: 54 additions & 13 deletions src/scratch.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
#include "rose/rose_internal.h"
#include "util/fatbit.h"

#define SCRATCH_CACHE_ALIGN 64
#define SCRATCH_ARRAY_BUF 256

/**
* Determine the space required for a correctly aligned array of fatbit
* structure, laid out as:
Expand Down Expand Up @@ -88,7 +91,7 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
u32 som_attempted_size = proto->som_fatbit_size;

struct hs_scratch *s;
struct hs_scratch *s_tmp;
struct hs_scratch *s_tmp = *scratch;
size_t queue_size = queueCount * sizeof(struct mq);
size_t qmpq_size = queueCount * sizeof(struct queue_match);

Expand Down Expand Up @@ -117,17 +120,21 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {

/* the struct plus the allocated stuff plus padding for cacheline
* alignment */
const size_t alloc_size = sizeof(struct hs_scratch) + size + 256;
s_tmp = hs_scratch_alloc(alloc_size);
hs_error_t err = hs_check_alloc(s_tmp);
if (err != HS_SUCCESS) {
hs_scratch_free(s_tmp);
*scratch = NULL;
return err;
const size_t alloc_size = sizeof(struct hs_scratch) + size +
SCRATCH_CACHE_ALIGN + SCRATCH_ARRAY_BUF;

if (!s_tmp) {
s_tmp = hs_scratch_alloc(alloc_size);
hs_error_t err = hs_check_alloc(s_tmp);
if (err != HS_SUCCESS) {
hs_scratch_free(s_tmp);
*scratch = NULL;
return err;
}
}

memset(s_tmp, 0, alloc_size);
s = ROUNDUP_PTR(s_tmp, 64);
s = ROUNDUP_PTR(s_tmp, SCRATCH_CACHE_ALIGN);
DEBUG_PRINTF("allocated %zu bytes at %p but realigning to %p\n", alloc_size, s_tmp, s);
DEBUG_PRINTF("sizeof %zu\n", sizeof(struct hs_scratch));
*s = *proto;
Expand Down Expand Up @@ -187,7 +194,7 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
s->tStateSize = tStateSize;
current += tStateSize;

current = ROUNDUP_PTR(current, 64);
current = ROUNDUP_PTR(current, SCRATCH_CACHE_ALIGN);

assert(ISALIGNED_N(current, 8));
s->deduper.som_start_log[0] = (u64a *)current;
Expand Down Expand Up @@ -221,7 +228,7 @@ hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
s->som_attempted_set = (struct fatbit *)current;
current += som_attempted_size;

current = ROUNDUP_PTR(current, 64);
current = ROUNDUP_PTR(current, SCRATCH_CACHE_ALIGN);
assert(ISALIGNED_CL(current));
s->fullState = (char *)current;
s->fullStateSize = fullStateSize;
Expand Down Expand Up @@ -275,7 +282,8 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
int resize = 0;

hs_scratch_t *proto;
hs_scratch_t *proto_tmp = hs_scratch_alloc(sizeof(struct hs_scratch) + 256);
hs_scratch_t *proto_tmp = hs_scratch_alloc(sizeof(struct hs_scratch) +
SCRATCH_CACHE_ALIGN + SCRATCH_ARRAY_BUF);
hs_error_t proto_ret = hs_check_alloc(proto_tmp);
if (proto_ret != HS_SUCCESS) {
hs_scratch_free(proto_tmp);
Expand All @@ -284,7 +292,7 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
return proto_ret;
}

proto = ROUNDUP_PTR(proto_tmp, 64);
proto = ROUNDUP_PTR(proto_tmp, SCRATCH_CACHE_ALIGN);

if (*scratch) {
*proto = **scratch;
Expand Down Expand Up @@ -369,6 +377,7 @@ hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
if (resize) {
if (*scratch) {
hs_scratch_free((*scratch)->scratch_alloc);
*scratch = NULL;
}

hs_error_t alloc_ret = alloc_scratch(proto, scratch);
Expand Down Expand Up @@ -404,6 +413,24 @@ hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
return HS_SUCCESS;
}

HS_PUBLIC_API
hs_error_t HS_CDECL hs_clone_scratch_at(const hs_scratch_t *src,
hs_scratch_t **dest) {
if (!dest || !*dest || !src ||
!ISALIGNED_CL(src) || src->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}

hs_error_t ret = alloc_scratch(src, dest);
if (ret != HS_SUCCESS) {
*dest = NULL;
return ret;
}

assert(!(*dest)->in_use);
return HS_SUCCESS;
}

HS_PUBLIC_API
hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch) {
if (scratch) {
Expand Down Expand Up @@ -439,3 +466,17 @@ hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch, size_t *size) {

return HS_SUCCESS;
}

HS_PUBLIC_API
hs_error_t HS_CDECL hs_scratch_memaddr(const hs_scratch_t *scratch, char **memaddr) {
if (!memaddr || !scratch || !ISALIGNED_CL(scratch) ||
scratch->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}

assert(scratch->scratch_alloc);
*memaddr = scratch->scratch_alloc;

return HS_SUCCESS;
}