Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ xnnpack_cc_library(
"include/xnnpack.h",
],
deps = [
":fingerprint_id",
"@pthreadpool",
],
)
Expand Down Expand Up @@ -773,6 +774,54 @@ xnnpack_cc_library(
],
)

xnnpack_cc_library(
name = "fingerprint_id",
srcs = ["src/operators/fingerprint_id.c"],
hdrs = [
"src/operators/fingerprint_id.h",
"src/operators/fingerprint_id.h.inc",
],
)

xnnpack_cc_library(
name = "fingerprint_cache",
srcs = ["src/operators/fingerprint_cache.c"],
hdrs = ["src/operators/fingerprint_cache.h"],
deps = [
":allocator",
":cache",
":fingerprint_id",
":init_once",
":mutex",
":operator_delete",
":xnnpack_h",
],
)

xnnpack_cc_library(
name = "fingerprint_check",
srcs = ["src/xnnpack/fingerprint_check.c"],
deps = [
":fingerprint_cache",
":fingerprint_id",
":operators",
":xnnpack_h",
],
)

xnnpack_cc_library(
name = "operator_delete",
srcs = ["src/operator-delete.c"],
deps = [
":allocator",
":logging",
":operator_h",
":operator_utils",
":params",
":xnnpack_h",
],
)

xnnpack_cc_library(
name = "operators",
srcs = OPERATOR_SRCS,
Expand Down Expand Up @@ -804,6 +853,7 @@ xnnpack_cc_library(
":microparams_init",
":node_type",
":normalization",
":operator_delete",
":operator_type",
":operator_utils",
":pack_lh",
Expand Down Expand Up @@ -932,6 +982,7 @@ xnnpack_cc_library(
"//:allocator",
"//:build_identifier", # build_cleaner: keep
"//:common", # build_cleaner: keep
"//:fingerprint_id",
"//:init_once",
"//:logging",
"//:math", # build_cleaner: keep
Expand Down
14 changes: 11 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,10 @@ IF(XNNPACK_BUILD_LIBRARY)
ADD_LIBRARY(xnnpack-allocator OBJECT src/allocator.c)
ADD_LIBRARY(xnnpack-cache OBJECT src/cache.c)
ADD_LIBRARY(xnnpack-datatype OBJECT src/datatype.c)
ADD_LIBRARY(xnnpack-operator-delete OBJECT src/operator-delete.c)
ADD_LIBRARY(xnnpack-fingerprint-id OBJECT src/operators/fingerprint_id.c)
ADD_LIBRARY(xnnpack-fingerprint-cache OBJECT src/operators/fingerprint_cache.c)
ADD_LIBRARY(xnnpack-fingerprint-check OBJECT src/xnnpack/fingerprint_check.c)
ADD_LIBRARY(xnnpack-memory OBJECT src/memory.c)
ADD_LIBRARY(xnnpack-microkernel-utils OBJECT src/microkernel-utils.c)
ADD_LIBRARY(xnnpack-mutex OBJECT src/mutex.c)
Expand All @@ -962,21 +966,25 @@ IF(XNNPACK_BUILD_LIBRARY)
TARGET_LINK_LIBRARIES(xnnpack-allocator PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-cache PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-datatype PRIVATE xnnpack-base)
TARGET_LINK_LIBRARIES(xnnpack-operator-delete PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-memory PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-microkernel-utils PRIVATE xnnpack-base xnnpack-hardware-config xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-mutex PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-operators PRIVATE xnnpack-base xnnpack-allocator xnnpack-indirection
xnnpack-logging xnnpack-microkernel-utils xnnpack-normalization xnnpack-operator-utils xnnpack-pack-lh xnnpack-packing
xnnpack-reference-ukernels xnnpack-datatype)
TARGET_LINK_LIBRARIES(xnnpack-fingerprint-cache PRIVATE xnnpack-base xnnpack-allocator xnnpack-cache xnnpack-mutex xnnpack-operator-delete)
TARGET_LINK_LIBRARIES(xnnpack-fingerprint-check PRIVATE xnnpack-base xnnpack-fingerprint-cache xnnpack-operators)
TARGET_LINK_LIBRARIES(xnnpack-operator-run PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-operator-utils PRIVATE xnnpack-base xnnpack-logging)
TARGET_LINK_LIBRARIES(xnnpack-reference-ukernels PRIVATE xnnpack-base xnnpack-datatype)
TARGET_LINK_LIBRARIES(xnnpack-subgraph PRIVATE xnnpack-base xnnpack-allocator xnnpack-logging xnnpack-memory xnnpack-mutex xnnpack-operators xnnpack-operator-run xnnpack-datatype)
TARGET_LINK_LIBRARIES(XNNPACK PRIVATE xnnpack-base xnnpack-allocator xnnpack-cache
xnnpack-hardware-config xnnpack-indirection xnnpack-memory xnnpack-microkernel-utils xnnpack-microparams-init
xnnpack-mutex xnnpack-normalization xnnpack-operators xnnpack-operator-run xnnpack-operator-utils xnnpack-pack-lh xnnpack-packing
xnnpack-microkernels-prod xnnpack-subgraph xnnpack-datatype xnnpack-reference-ukernels)
TARGET_LINK_LIBRARIES(XNNPACK PUBLIC pthreadpool xnnpack-logging)
xnnpack-mutex xnnpack-normalization xnnpack-operators xnnpack-operator-run
xnnpack-operator-utils xnnpack-pack-lh xnnpack-packing xnnpack-fingerprint-id xnnpack-fingerprint-cache xnnpack-microkernels-prod
xnnpack-subgraph xnnpack-datatype xnnpack-reference-ukernels)
TARGET_LINK_LIBRARIES(XNNPACK PUBLIC pthreadpool xnnpack-logging xnnpack-fingerprint-check)
SET_TARGET_PROPERTIES(XNNPACK PROPERTIES C_EXTENSIONS YES)
ENDIF()
IF(NOT MSVC)
Expand Down
1 change: 0 additions & 1 deletion build_srcs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Lists of target-specific sources used to build XNNPACK.
"""

OPERATOR_SRCS = [
"src/operator-delete.c",
"src/operator-run.c",
"src/operators/argmax-pooling-nhwc.c",
"src/operators/average-pooling-nhwc.c",
Expand Down
24 changes: 24 additions & 0 deletions include/experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <stdint.h>

#include "include/xnnpack.h"
#include "src/operators/fingerprint_id.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -98,6 +99,29 @@ enum xnn_status xnn_update_runtime_with_threadpool(
xnn_runtime_t runtime,
xnn_threadpool_t threadpool);


typedef struct xnn_fingerprint* xnn_fingerprint_t;

struct xnn_fingerprint {
enum xnn_fingerprint_id id;
uint32_t value;
};

/// Check whether the given configuration matches one that is currently in use.
///
/// @returns True if the configuration matches.
bool xnn_check_fingerprint(struct xnn_fingerprint fingerprint);

/// Return the fingerprint corresponding to the given id or NULL if it wasn't
/// set.
const struct xnn_fingerprint* xnn_get_fingerprint(enum xnn_fingerprint_id id);

/// Set the given fingerprint.
void xnn_set_fingerprint(struct xnn_fingerprint fingerprint);

/// Clear all fingerprints that were computed until now.
void xnn_clear_fingerprints();

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
5 changes: 4 additions & 1 deletion include/xnnpack.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Facebook, Inc. and its affiliates.
// All rights reserved.
//
// Copyright 2019 Google LLC
// Copyright 2019-2025 Google LLC
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
Expand All @@ -15,6 +15,7 @@
#include <stddef.h>
#include <stdint.h>

#include "src/operators/fingerprint_id.h"
#include <pthreadpool.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -2297,6 +2298,8 @@ struct xnn_weights_cache_look_up_key {
const void* kernel;
/// Pointer to the original bias, could be NULL.
const void* bias;

enum xnn_fingerprint_id fingerprint_id;
};

/// A group of function pointers to manage weights cache. All functions may be
Expand Down
178 changes: 178 additions & 0 deletions src/operators/fingerprint_cache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2025 Google LLC
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

#include "src/operators/fingerprint_cache.h"

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

#include "include/experimental.h"
#include "include/xnnpack.h"
#include "src/operators/fingerprint_id.h"
#include "src/xnnpack/allocator.h"
#include "src/xnnpack/cache.h"
#include "src/xnnpack/init-once.h"
#include "src/xnnpack/mutex.h"

#define XNN_FINGERPRINT_MAX_COUNT 256
static struct xnn_fingerprint fingerprint_vector[XNN_FINGERPRINT_MAX_COUNT];
static uint32_t fingerprint_vector_size = 0;

static struct xnn_mutex mutex;
XNN_INIT_ONCE_GUARD(mutex);

static void init_mutex_config() { xnn_mutex_init(&mutex); }

const struct xnn_fingerprint* xnn_get_fingerprint(
const enum xnn_fingerprint_id id) {
XNN_INIT_ONCE(mutex);
uint32_t i = 0;
xnn_mutex_lock(&mutex);
for (; i < fingerprint_vector_size; ++i) {
if (fingerprint_vector[i].id == id) {
break;
}
}
xnn_mutex_unlock(&mutex);
return i < fingerprint_vector_size ? fingerprint_vector + i : NULL;
}

void xnn_set_fingerprint(const struct xnn_fingerprint fingerprint) {
XNN_INIT_ONCE(mutex);
uint32_t i = 0;
xnn_mutex_lock(&mutex);
for (; i < fingerprint_vector_size; ++i) {
if (fingerprint_vector[i].id == fingerprint.id) {
fingerprint_vector[i] = fingerprint;
}
}
xnn_mutex_unlock(&mutex);
if (i < fingerprint_vector_size) {
return;
}
assert(fingerprint_vector_size < XNN_FINGERPRINT_MAX_COUNT);
fingerprint_vector[fingerprint_vector_size++] = fingerprint;
}

void xnn_clear_fingerprints() {
XNN_INIT_ONCE(mutex);
xnn_mutex_lock(&mutex);
fingerprint_vector_size = 0;
xnn_mutex_unlock(&mutex);
}

// The context for an XNNPack weight cache provider that we pass to operator
// `create` functions when we want to fingerprint them.
struct fingerprint_cache_context {
void* buffer;
size_t bytes;
uint32_t hash;
};

static size_t fingerprint_cache_look_up(
void* context, const struct xnn_weights_cache_look_up_key* cache_key) {
return XNN_CACHE_NOT_FOUND;
}

static void* fingerprint_cache_reserve_space(void* const context, size_t n) {
struct fingerprint_cache_context* const ctx = context;
assert(ctx);
if (ctx->buffer && ctx->bytes < n) {
xnn_release_simd_memory(ctx->buffer);
ctx->buffer = NULL;
}
if (ctx->buffer == NULL) {
ctx->buffer = xnn_allocate_simd_memory(n);
ctx->bytes = ctx->buffer ? n : 0;
}
return ctx->buffer;
}

static size_t fingerprint_cache_look_up_or_insert(
void* context, const struct xnn_weights_cache_look_up_key* cache_key,
void* ptr, size_t size) {
assert(context);
struct fingerprint_cache_context* const ctx = context;
ctx->hash = murmur_hash3(ptr, size, /*seed=*/ctx->hash);
return 0;
}

static bool fingerprint_cache_is_finalized(void* context) { return false; }

static void* fingerprint_cache_offset_to_addr(void* context, size_t offset) {
assert(context);
struct fingerprint_cache_context* const ctx = context;
return ctx->buffer;
}

static enum xnn_status fingerprint_cache_delete_cache(void* context) {
struct fingerprint_cache_context* const ctx = context;
if (ctx) {
if (ctx->buffer) {
xnn_release_simd_memory(ctx->buffer);
}
*ctx = (struct fingerprint_cache_context){0};
}
return xnn_status_success;
}

struct fingerprint_context create_fingerprint_context(
const enum xnn_fingerprint_id fingerprint_id) {
struct fingerprint_context context = {
.status = xnn_status_uninitialized,
.fingerprint_id = fingerprint_id,
.cache =
(struct xnn_weights_cache_provider){
.context = NULL,
.look_up = fingerprint_cache_look_up,
.reserve_space = fingerprint_cache_reserve_space,
.look_up_or_insert = fingerprint_cache_look_up_or_insert,
.is_finalized = fingerprint_cache_is_finalized,
.offset_to_addr = fingerprint_cache_offset_to_addr,
.delete_cache = fingerprint_cache_delete_cache},
.op = NULL,
};
if (context.fingerprint_id == xnn_fingerprint_id_unknown) {
context.status = xnn_status_unsupported_parameter;
} else if (xnn_get_fingerprint(context.fingerprint_id)) {
context.status = xnn_status_success;
} else {
// Do this after the checks to avoid a memory allocation when unnecessary.
context.cache.context = xnn_allocate_zero_memory(sizeof(struct fingerprint_cache_context));
}
return context;
}

static void free_fingerprint_cache_provider(
struct xnn_weights_cache_provider* const provider) {
if (provider) {
provider->delete_cache(provider->context);
if (provider->context) {
xnn_release_memory(provider->context);
}
}
}

void finalize_fingerprint_context(struct fingerprint_context* const context) {
assert(context);
if (context->status == xnn_status_uninitialized) {
xnn_set_fingerprint((struct xnn_fingerprint){
.id = context->fingerprint_id,
.value = fingerprint_cache_get_fingerprint(&context->cache)});
}
free_fingerprint_cache_provider(&context->cache);
if (context->op) {
xnn_delete_operator(context->op);
}
}

uint32_t fingerprint_cache_get_fingerprint(
const struct xnn_weights_cache_provider* const provider) {
assert(provider);
assert(provider->context);
return ((struct fingerprint_cache_context*)provider->context)->hash;
}
Loading
Loading