Skip to content

Commit 5171eb7

Browse files
author
Gourav Kumar
committed
v3.0-alpha Week 4: Stable C++ ABI layer
- Add stable C API with opaque handles - Add context management (per-GPU state) - Add versioned ABI (binary compatibility) - Add error handling (no exceptions across boundary) - Add ABI compatibility tests - Add version header generation Enterprise features: - Binary stable across minor versions - No C++ in public headers - Thread-safe error handling - Opaque implementation (can change internals) - ABI version checking This is the foundation for long-term API stability.
1 parent 738679a commit 5171eb7

File tree

7 files changed

+754
-0
lines changed

7 files changed

+754
-0
lines changed

examples/c_api_example.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//===- c_api_example.c - Using SparseFlow C API -------------------------===//
2+
3+
#include "sparseflow/c_api.h"
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
7+
int main() {
8+
printf("SparseFlow C API Example\n");
9+
printf("========================\n\n");
10+
11+
// Check version
12+
SparseFlowVersion version = sparseflow_get_version();
13+
printf("Library version: %d.%d.%d\n",
14+
version.major, version.minor, version.patch);
15+
16+
// Check ABI compatibility
17+
if (!sparseflow_is_abi_compatible(1, 0)) {
18+
fprintf(stderr, "ABI version mismatch!\n");
19+
return 1;
20+
}
21+
printf("ABI: Compatible\n\n");
22+
23+
// Create context
24+
SparseFlowContext ctx;
25+
SparseFlowStatus status = sparseflow_create_context(&ctx, 0);
26+
27+
if (status != SPARSEFLOW_SUCCESS) {
28+
fprintf(stderr, "Failed to create context: %s\n",
29+
sparseflow_get_error_string(status));
30+
fprintf(stderr, "Details: %s\n", sparseflow_get_last_error());
31+
return 1;
32+
}
33+
34+
// Get GPU info
35+
int compute_cap, sm_count;
36+
size_t total_mem;
37+
sparseflow_get_device_info(ctx, &compute_cap, &sm_count, &total_mem);
38+
39+
printf("GPU Information:\n");
40+
printf(" Compute capability: SM%d\n", compute_cap);
41+
printf(" SM count: %d\n", sm_count);
42+
printf(" Total memory: %.2f GB\n", total_mem / (1024.0*1024.0*1024.0));
43+
44+
// Check 2:4 sparse support
45+
if (compute_cap >= 80) {
46+
printf(" ✓ 2:4 sparse supported\n");
47+
} else {
48+
printf(" ✗ 2:4 sparse NOT supported (requires SM80+)\n");
49+
}
50+
51+
printf("\n");
52+
53+
// Configure kernel
54+
SparseFlowKernelConfig config = {
55+
.tile_m = 128,
56+
.tile_n = 128,
57+
.tile_k = 64,
58+
.epilogue = {
59+
.kind = SPARSEFLOW_EPILOGUE_SILU,
60+
.params = NULL,
61+
.params_size = 0
62+
}
63+
};
64+
65+
SparseFlowKernel kernel;
66+
status = sparseflow_compile_kernel(ctx, &kernel, &config);
67+
68+
if (status == SPARSEFLOW_SUCCESS) {
69+
printf("Kernel compiled successfully\n");
70+
printf(" Configuration: %dx%dx%d tiles\n",
71+
config.tile_m, config.tile_n, config.tile_k);
72+
printf(" Epilogue: SiLU\n");
73+
74+
// Clean up kernel
75+
sparseflow_destroy_kernel(kernel);
76+
} else {
77+
printf("Kernel compilation not yet implemented\n");
78+
}
79+
80+
// Clean up context
81+
sparseflow_destroy_context(ctx);
82+
83+
printf("\n✅ Example complete!\n");
84+
return 0;
85+
}

include/sparseflow/c_api.h

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
//===- c_api.h - SparseFlow Stable C API --------------------------------===//
2+
//
3+
// Stable ABI v1 - Binary compatible across minor versions
4+
// Breaking changes only on major version bump
5+
//
6+
//===----------------------------------------------------------------------===//
7+
8+
#ifndef SPARSEFLOW_C_API_H
9+
#define SPARSEFLOW_C_API_H
10+
11+
#include <stddef.h>
12+
#include <stdint.h>
13+
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
// ABI version - increment on breaking changes
19+
#define SPARSEFLOW_ABI_VERSION_MAJOR 1
20+
#define SPARSEFLOW_ABI_VERSION_MINOR 0
21+
#define SPARSEFLOW_ABI_VERSION_PATCH 0
22+
23+
// Export macro
24+
#if defined(_WIN32)
25+
#ifdef SPARSEFLOW_BUILD_SHARED
26+
#define SPARSEFLOW_API __declspec(dllexport)
27+
#else
28+
#define SPARSEFLOW_API __declspec(dllimport)
29+
#endif
30+
#else
31+
#define SPARSEFLOW_API __attribute__((visibility("default")))
32+
#endif
33+
34+
//===----------------------------------------------------------------------===//
35+
// Opaque handles (hide implementation details)
36+
//===----------------------------------------------------------------------===//
37+
38+
typedef struct SparseFlowContext_* SparseFlowContext;
39+
typedef struct SparseFlowKernel_* SparseFlowKernel;
40+
typedef struct SparseFlowTensor_* SparseFlowTensor;
41+
42+
//===----------------------------------------------------------------------===//
43+
// Error handling
44+
//===----------------------------------------------------------------------===//
45+
46+
typedef enum {
47+
SPARSEFLOW_SUCCESS = 0,
48+
SPARSEFLOW_ERROR_INVALID_ARGUMENT = 1,
49+
SPARSEFLOW_ERROR_OUT_OF_MEMORY = 2,
50+
SPARSEFLOW_ERROR_CUDA_ERROR = 3,
51+
SPARSEFLOW_ERROR_NOT_SUPPORTED = 4,
52+
SPARSEFLOW_ERROR_INVALID_HANDLE = 5,
53+
SPARSEFLOW_ERROR_COMPILATION_FAILED = 6,
54+
SPARSEFLOW_ERROR_ABI_MISMATCH = 7,
55+
} SparseFlowStatus;
56+
57+
// Get error message for status code
58+
SPARSEFLOW_API const char* sparseflow_get_error_string(SparseFlowStatus status);
59+
60+
// Get last error message (thread-local)
61+
SPARSEFLOW_API const char* sparseflow_get_last_error();
62+
63+
//===----------------------------------------------------------------------===//
64+
// Version info
65+
//===----------------------------------------------------------------------===//
66+
67+
typedef struct {
68+
int major;
69+
int minor;
70+
int patch;
71+
} SparseFlowVersion;
72+
73+
SPARSEFLOW_API SparseFlowVersion sparseflow_get_version();
74+
75+
// Check ABI compatibility
76+
SPARSEFLOW_API int sparseflow_is_abi_compatible(int major, int minor);
77+
78+
//===----------------------------------------------------------------------===//
79+
// Context management
80+
//===----------------------------------------------------------------------===//
81+
82+
// Create context for specific GPU
83+
SPARSEFLOW_API SparseFlowStatus sparseflow_create_context(
84+
SparseFlowContext* ctx,
85+
int device_id
86+
);
87+
88+
// Destroy context
89+
SPARSEFLOW_API SparseFlowStatus sparseflow_destroy_context(
90+
SparseFlowContext ctx
91+
);
92+
93+
// Get GPU info from context
94+
SPARSEFLOW_API SparseFlowStatus sparseflow_get_device_info(
95+
SparseFlowContext ctx,
96+
int* compute_capability,
97+
int* sm_count,
98+
size_t* total_memory
99+
);
100+
101+
//===----------------------------------------------------------------------===//
102+
// Epilogue configuration
103+
//===----------------------------------------------------------------------===//
104+
105+
typedef enum {
106+
SPARSEFLOW_EPILOGUE_NONE = 0,
107+
SPARSEFLOW_EPILOGUE_RELU = 1,
108+
SPARSEFLOW_EPILOGUE_SILU = 2,
109+
SPARSEFLOW_EPILOGUE_GELU = 3,
110+
SPARSEFLOW_EPILOGUE_BIAS = 4,
111+
SPARSEFLOW_EPILOGUE_BIAS_RELU = 5,
112+
SPARSEFLOW_EPILOGUE_BIAS_SILU = 6,
113+
} SparseFlowEpilogue;
114+
115+
typedef struct {
116+
SparseFlowEpilogue kind;
117+
const void* params; // Optional parameters (e.g., bias pointer)
118+
size_t params_size; // Size of params in bytes
119+
} SparseFlowEpilogueConfig;
120+
121+
//===----------------------------------------------------------------------===//
122+
// Kernel compilation
123+
//===----------------------------------------------------------------------===//
124+
125+
typedef struct {
126+
int tile_m; // Tile size M (0 = auto-select)
127+
int tile_n; // Tile size N (0 = auto-select)
128+
int tile_k; // Tile size K (0 = auto-select)
129+
SparseFlowEpilogueConfig epilogue;
130+
} SparseFlowKernelConfig;
131+
132+
// Compile kernel with given configuration
133+
SPARSEFLOW_API SparseFlowStatus sparseflow_compile_kernel(
134+
SparseFlowContext ctx,
135+
SparseFlowKernel* kernel,
136+
const SparseFlowKernelConfig* config
137+
);
138+
139+
// Destroy kernel
140+
SPARSEFLOW_API SparseFlowStatus sparseflow_destroy_kernel(
141+
SparseFlowKernel kernel
142+
);
143+
144+
//===----------------------------------------------------------------------===//
145+
// Tensor operations
146+
//===----------------------------------------------------------------------===//
147+
148+
typedef enum {
149+
SPARSEFLOW_DTYPE_FP16 = 0,
150+
SPARSEFLOW_DTYPE_FP32 = 1,
151+
SPARSEFLOW_DTYPE_INT8 = 2,
152+
} SparseFlowDataType;
153+
154+
// Execute sparse GEMM: C = A @ Bc
155+
SPARSEFLOW_API SparseFlowStatus sparseflow_sparse_gemm(
156+
SparseFlowKernel kernel,
157+
const void* A, // Dense matrix (M × K)
158+
const void* Bc, // Compressed sparse matrix
159+
void* C, // Output matrix (M × N)
160+
int M, int N, int K,
161+
SparseFlowDataType dtype,
162+
void* stream // CUDA stream (or NULL for default)
163+
);
164+
165+
// Compress dense tensor to 2:4 format
166+
SPARSEFLOW_API SparseFlowStatus sparseflow_compress_2_4(
167+
SparseFlowContext ctx,
168+
const void* dense, // Input dense tensor
169+
void* compressed, // Output compressed tensor (50% size)
170+
void* metadata, // Output metadata
171+
int M, int N,
172+
SparseFlowDataType dtype
173+
);
174+
175+
// Validate 2:4 sparsity pattern
176+
SPARSEFLOW_API SparseFlowStatus sparseflow_validate_2_4(
177+
const void* tensor,
178+
int M, int N,
179+
SparseFlowDataType dtype,
180+
int* is_valid // Output: 1 if valid, 0 if not
181+
);
182+
183+
//===----------------------------------------------------------------------===//
184+
// Benchmarking utilities
185+
//===----------------------------------------------------------------------===//
186+
187+
typedef struct {
188+
double elapsed_ms; // Elapsed time in milliseconds
189+
double tflops_effective; // Effective TFLOPS
190+
double tflops_real; // Real TFLOPS (accounting for sparsity)
191+
double bandwidth_gb_s; // Memory bandwidth (GB/s)
192+
} SparseFlowBenchmarkResult;
193+
194+
// Benchmark kernel performance
195+
SPARSEFLOW_API SparseFlowStatus sparseflow_benchmark_kernel(
196+
SparseFlowKernel kernel,
197+
int M, int N, int K,
198+
int num_iterations,
199+
SparseFlowBenchmarkResult* result
200+
);
201+
202+
#ifdef __cplusplus
203+
}
204+
#endif
205+
206+
#endif // SPARSEFLOW_C_API_H

include/sparseflow/version.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Auto-generated version header
2+
#ifndef SPARSEFLOW_VERSION_H
3+
#define SPARSEFLOW_VERSION_H
4+
5+
#define SPARSEFLOW_VERSION_MAJOR 3
6+
#define SPARSEFLOW_VERSION_MINOR 0
7+
#define SPARSEFLOW_VERSION_PATCH 0
8+
#define SPARSEFLOW_VERSION_STRING "3.0.0-alpha+738679a"
9+
10+
#endif // SPARSEFLOW_VERSION_H

scripts/generate_version.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
# Generate version header from git tags
3+
4+
VERSION_FILE="include/sparseflow/version.h"
5+
6+
# Get version from git
7+
if git describe --tags --exact-match 2>/dev/null; then
8+
VERSION=$(git describe --tags --exact-match)
9+
else
10+
VERSION="3.0.0-alpha+$(git rev-parse --short HEAD)"
11+
fi
12+
13+
# Parse version
14+
MAJOR=$(echo $VERSION | cut -d. -f1 | sed 's/v//')
15+
MINOR=$(echo $VERSION | cut -d. -f2)
16+
PATCH=$(echo $VERSION | cut -d. -f3 | cut -d- -f1 | cut -d+ -f1)
17+
18+
cat > $VERSION_FILE << EOH
19+
// Auto-generated version header
20+
#ifndef SPARSEFLOW_VERSION_H
21+
#define SPARSEFLOW_VERSION_H
22+
23+
#define SPARSEFLOW_VERSION_MAJOR $MAJOR
24+
#define SPARSEFLOW_VERSION_MINOR $MINOR
25+
#define SPARSEFLOW_VERSION_PATCH $PATCH
26+
#define SPARSEFLOW_VERSION_STRING "$VERSION"
27+
28+
#endif // SPARSEFLOW_VERSION_H
29+
EOH
30+
31+
echo "✅ Generated $VERSION_FILE"
32+
echo " Version: $VERSION"

0 commit comments

Comments
 (0)