Skip to content

Commit a615253

Browse files
authored
Merge pull request #3616 from vladpaiu/bucket_allocator
Add multi-lock allocator
2 parents 6af684e + 7071ece commit a615253

9 files changed

Lines changed: 1329 additions & 21 deletions

Makefile.conf.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ DEFS+= -DF_MALLOC #Fast memory allocator with minimal runtime overhead
9797
DEFS+= -DQ_MALLOC #Quality assurance memory allocator with runtime safety checks
9898
DEFS+= -DHP_MALLOC #High performance allocator with fine-grained locking
9999
DEFS+= -DDBG_MALLOC #Include additional, debug-enabled allocator flavors
100+
DEFS+= -DF_PARALLEL_MALLOC #Fast memory allocator with paralel buckets
100101
#DEFS+= -DQM_DBG_MALLOC_HIST=3 #Size of debug history for Q_MALLOC (default is 1)
101102
#DEFS+= -DNO_DEBUG #Compile out all debug messages
102103
#DEFS+= -DNO_LOG #Compile out all logging

mem/common.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ int parse_mm(const char *mm_name, enum osips_mm *mm)
6060
return 0;
6161
}
6262

63+
if (!strcasecmp(mm_name, "F_PARALLEL_MALLOC")) {
64+
*mm = MM_F_PARALLEL_MALLOC;
65+
return 0;
66+
}
67+
6368
#ifdef DBG_MALLOC
6469
if (!strcasecmp(mm_name, "F_MALLOC_DBG")) {
6570
*mm = MM_F_MALLOC_DBG;
@@ -75,6 +80,11 @@ int parse_mm(const char *mm_name, enum osips_mm *mm)
7580
*mm = MM_HP_MALLOC_DBG;
7681
return 0;
7782
}
83+
84+
if (!strcasecmp(mm_name, "F_PARALLEL_MALLOC_DBG")) {
85+
*mm = MM_F_PARALLEL_MALLOC_DBG;
86+
return 0;
87+
}
7888
#endif
7989

8090
return -1;

mem/common.h

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,42 @@
2323
#ifndef mem_common_h
2424
#define mem_common_h
2525

26+
#include "../lock_ops.h"
27+
28+
#define TOTAL_F_PARALLEL_POOLS 32
29+
2630
extern void *mem_block;
2731
extern void *shm_block;
2832
extern void *shm_dbg_block;
2933
extern void *rpm_block;
34+
extern void **shm_blocks;
35+
extern int init_done;
36+
extern gen_lock_t *hash_locks[TOTAL_F_PARALLEL_POOLS];
3037

3138
#include "meminfo.h"
3239

33-
#if !defined(F_MALLOC) && !defined(Q_MALLOC) && !defined(HP_MALLOC)
34-
#error "no memory allocator selected"
35-
/* if exactly an allocator was selected, let's inline it! */
36-
#elif ((!defined Q_MALLOC && !defined HP_MALLOC) || \
37-
(!defined F_MALLOC && !defined HP_MALLOC) || \
38-
(!defined F_MALLOC && !defined Q_MALLOC))
40+
#if !defined(F_MALLOC) && !defined(Q_MALLOC) && !defined(HP_MALLOC) && !defined(F_PARALLEL_MALLOC)
41+
#error "no memory allocator selected"b
42+
43+
/* if exactly one allocator was selected, let's inline it! */
44+
#elif ((!defined(F_MALLOC) && !defined(Q_MALLOC) && !defined(HP_MALLOC)) || \
45+
(!defined(F_MALLOC) && !defined(Q_MALLOC) && !defined(F_PARALLEL_MALLOC)) || \
46+
(!defined(F_MALLOC) && !defined(HP_MALLOC) && !defined(F_PARALLEL_MALLOC)) || \
47+
(!defined(Q_MALLOC) && !defined(HP_MALLOC) && !defined(F_PARALLEL_MALLOC)))
3948
#define INLINE_ALLOC
4049
#endif
4150

51+
4252
enum osips_mm {
4353
MM_NONE,
4454
MM_F_MALLOC,
4555
MM_Q_MALLOC,
4656
MM_HP_MALLOC,
57+
MM_F_PARALLEL_MALLOC,
4758
MM_F_MALLOC_DBG,
4859
MM_Q_MALLOC_DBG,
4960
MM_HP_MALLOC_DBG,
61+
MM_F_PARALLEL_MALLOC_DBG,
5062
};
5163

5264
#if defined F_MALLOC
@@ -61,6 +73,10 @@ enum osips_mm {
6173
#include "hp_malloc.h"
6274
#endif
6375

76+
#if defined F_PARALLEL_MALLOC
77+
#include "f_parallel_malloc.h"
78+
#endif
79+
6480
extern int mem_warming_enabled;
6581
extern char *mem_warming_pattern_file;
6682
extern int mem_warming_percentage;
@@ -77,8 +93,10 @@ int parse_mm(const char *mm_name, enum osips_mm *mm);
7793
(mm) == MM_F_MALLOC ? "F_MALLOC" : \
7894
(mm) == MM_Q_MALLOC ? "Q_MALLOC" : \
7995
(mm) == MM_HP_MALLOC ? "HP_MALLOC" : \
96+
(mm) == MM_F_PARALLEL_MALLOC ? "F_PARALLEL_MALLOC" : \
8097
(mm) == MM_F_MALLOC_DBG ? "F_MALLOC_DBG" : \
8198
(mm) == MM_Q_MALLOC_DBG ? "Q_MALLOC_DBG" : \
99+
(mm) == MM_F_PARALLEL_MALLOC_DBG ? "F_PARALLEL_MALLOC_DBG" : \
82100
(mm) == MM_HP_MALLOC_DBG ? "HP_MALLOC_DBG" : "unknown")
83101

84102
#ifdef DBG_MALLOC

mem/f_parallel_malloc.c

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
/*
2+
* Copyright (C) 2001-2003 FhG Fokus
3+
* Copyright (C) 2025 OpenSIPS Project
4+
*
5+
* This file is part of opensips, a free SIP server.
6+
*
7+
* opensips is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version
11+
*
12+
* opensips is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#ifdef F_PARALLEL_MALLOC
23+
24+
#include <string.h>
25+
#include <stdio.h>
26+
#include <stdlib.h>
27+
28+
#include "f_parallel_malloc.h"
29+
#include "../dprint.h"
30+
#include "../globals.h"
31+
#include "../statistics.h"
32+
33+
#ifdef DBG_MALLOC
34+
#include "mem_dbg_hash.h"
35+
#endif
36+
37+
#include "../lib/dbg/struct_hist.h"
38+
39+
#define MIN_FRAG_SIZE ROUNDTO
40+
#define F_PARALLEL_FRAG_OVERHEAD (sizeof(struct parallel_frag))
41+
#define frag_is_free(_f) ((_f)->prev)
42+
43+
#define F_PARALLEL_FRAG_NEXT(f) \
44+
((struct parallel_frag *)((char *)(f) + sizeof(struct parallel_frag) + (f)->size))
45+
46+
#define max(a,b) ( (a)>(b)?(a):(b))
47+
48+
/* ROUNDTO= 2^k so the following works */
49+
#define ROUNDTO_MASK (~((unsigned long)ROUNDTO-1))
50+
#define ROUNDUP(s) (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
51+
#define ROUNDDOWN(s) ((s)&ROUNDTO_MASK)
52+
53+
/* finds the hash value for s, s=ROUNDTO multiple*/
54+
#define F_PARALLEL_GET_HASH(s) ( ((unsigned long)(s)<=F_PARALLEL_MALLOC_OPTIMIZE)?\
55+
(unsigned long)(s)/ROUNDTO: \
56+
F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
57+
F_PARALLEL_MALLOC_OPTIMIZE_FACTOR+1 )
58+
59+
#define F_PARALLEL_UN_HASH(h) ( ((unsigned long)(h)<=(F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO))?\
60+
(unsigned long)(h)*ROUNDTO: \
61+
1UL<<((unsigned long)(h)-F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO+\
62+
F_PARALLEL_MALLOC_OPTIMIZE_FACTOR-1)\
63+
)
64+
65+
static inline void parallel_free_minus(struct parallel_block *fm, unsigned long size)
66+
{
67+
68+
#if defined(DBG_MALLOC) || defined(STATISTICS)
69+
fm->real_used+=size;
70+
fm->used+=size;
71+
#endif
72+
}
73+
74+
75+
static inline void parallel_free_plus(struct parallel_block *fm, unsigned long size)
76+
{
77+
78+
#if defined(DBG_MALLOC) || defined(STATISTICS)
79+
fm->real_used-=size;
80+
fm->used-=size;
81+
#endif
82+
}
83+
84+
85+
/* computes hash number for big buckets*/
86+
inline static unsigned long big_hash_idx(unsigned long s)
87+
{
88+
unsigned long idx;
89+
/* s is rounded => s = k*2^n (ROUNDTO=2^n)
90+
* index= i such that 2^i > s >= 2^(i-1)
91+
*
92+
* => index = number of the first non null bit in s*/
93+
idx=sizeof(long)*8-1;
94+
for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
95+
return idx;
96+
}
97+
98+
#ifdef SHM_EXTRA_STATS
99+
#include "module_info.h"
100+
unsigned long parallel_stats_get_index(void *ptr)
101+
{
102+
if (!ptr)
103+
return GROUP_IDX_INVALID;
104+
105+
return F_PARALLEL_FRAG(ptr)->statistic_index;
106+
}
107+
108+
void parallel_stats_set_index(void *ptr, unsigned long idx)
109+
{
110+
if (!ptr)
111+
return;
112+
113+
F_PARALLEL_FRAG(ptr)->statistic_index = idx;
114+
}
115+
#endif
116+
117+
static inline void parallel_insert_free(struct parallel_block *fm, struct parallel_frag *frag)
118+
{
119+
struct parallel_frag **f;
120+
int hash;
121+
122+
hash=F_PARALLEL_GET_HASH(frag->size);
123+
f=&(fm->free_hash[hash].first);
124+
if (*f)
125+
(*f)->block_ptr = fm;
126+
if (frag->size > F_PARALLEL_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
127+
(different from 0.8.1[24] on
128+
purpose --andrei ) */
129+
for(; *f; f=&((*f)->u.nxt_free)){
130+
(*f)->block_ptr = fm;
131+
if (frag->size <= (*f)->size) break;
132+
}
133+
}
134+
135+
/*insert it here*/
136+
if (*f) {
137+
(*f)->block_ptr = fm;
138+
}
139+
140+
frag->prev = f;
141+
frag->u.nxt_free=*f;
142+
frag->block_ptr = fm;
143+
144+
if( *f ) {
145+
(*f)->block_ptr = fm;
146+
(*f)->prev = &(frag->u.nxt_free);
147+
frag->u.nxt_free->block_ptr = fm;
148+
}
149+
150+
*f=frag;
151+
fm->free_hash[hash].no++;
152+
153+
frag->block_ptr = fm;
154+
parallel_free_plus(fm, frag->size);
155+
}
156+
157+
static inline void parallel_remove_free(struct parallel_block *fm, struct parallel_frag *n)
158+
{
159+
struct parallel_frag **pf;
160+
int hash;
161+
162+
pf = n->prev;
163+
hash = F_PARALLEL_GET_HASH( n->size );
164+
165+
/* detach */
166+
if (*pf)
167+
(*pf)->block_ptr=fm;
168+
169+
*pf=n->u.nxt_free;
170+
if (*pf)
171+
(*pf)->block_ptr=fm;
172+
173+
if( n->u.nxt_free )
174+
n->u.nxt_free->prev = pf;
175+
176+
fm->free_hash[hash].no--;
177+
178+
n->prev = NULL;
179+
n->block_ptr = fm;
180+
181+
parallel_free_minus(fm , n->size);
182+
183+
};
184+
185+
186+
187+
188+
189+
/* init malloc and return a parallel_block*/
190+
struct parallel_block *parallel_malloc_init(char *address, unsigned long size, char *name, int idx)
191+
192+
{
193+
char *start;
194+
char *end;
195+
struct parallel_block *fm;
196+
unsigned long init_overhead;
197+
198+
/* make address and size multiple of 8*/
199+
start=(char*)ROUNDUP((unsigned long) address);
200+
LM_DBG("F_OPTIMIZE=%lu, /ROUNDTO=%lu, %lu-bytes aligned\n",
201+
F_PARALLEL_MALLOC_OPTIMIZE, F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO,
202+
(unsigned long)ROUNDTO);
203+
LM_DBG("F_HASH_SIZE=%lu, parallel_block size=%zu, frag_size=%zu\n",
204+
F_PARALLEL_HASH_SIZE, sizeof(struct parallel_block), sizeof(struct parallel_frag));
205+
LM_DBG("params (%p, %lu), start=%p\n", address, size, start);
206+
207+
if (size<(unsigned long)(start-address)) return 0;
208+
size-=(start-address);
209+
if (size <(MIN_FRAG_SIZE+F_PARALLEL_FRAG_OVERHEAD)) return 0;
210+
size=ROUNDDOWN(size);
211+
212+
init_overhead=(ROUNDUP(sizeof(struct parallel_block))+ 2 * F_PARALLEL_FRAG_OVERHEAD);
213+
214+
215+
if (size < init_overhead)
216+
{
217+
/* not enough mem to create our control structures !!!*/
218+
return 0;
219+
}
220+
end=start+size;
221+
fm=(struct parallel_block *)start;
222+
memset(fm, 0, sizeof(struct parallel_block));
223+
fm->name = name;
224+
fm->size=size;
225+
226+
fm->idx = idx;
227+
228+
#if defined(DBG_MALLOC) || defined(STATISTICS)
229+
fm->used=size-init_overhead;
230+
fm->real_used=size;
231+
fm->max_real_used=init_overhead;
232+
fm->fragments = 0;
233+
#endif
234+
235+
fm->first_frag=(struct parallel_frag *)(start+ROUNDUP(sizeof(struct parallel_block)));
236+
fm->last_frag=(struct parallel_frag *)(end-sizeof(struct parallel_frag));
237+
238+
fm->first_frag->block_ptr = fm;
239+
fm->last_frag->block_ptr = fm;
240+
241+
/* init initial fragment*/
242+
fm->first_frag->size=size-init_overhead;
243+
fm->last_frag->size=0;
244+
245+
fm->last_frag->prev=NULL;
246+
fm->first_frag->prev=NULL;
247+
248+
/* link initial fragment into the free list*/
249+
250+
parallel_insert_free(fm, fm->first_frag);
251+
252+
return fm;
253+
}
254+
255+
#include "f_parallel_malloc_dyn.h"
256+
257+
#if !defined INLINE_ALLOC && defined DBG_MALLOC
258+
#undef DBG_MALLOC
259+
#include "f_parallel_malloc_dyn.h"
260+
#define DBG_MALLOC
261+
#endif
262+
263+
#ifdef SHM_EXTRA_STATS
264+
void parallel_stats_core_init(struct parallel_block *fm, int core_index)
265+
{
266+
struct parallel_frag *f;
267+
268+
for (f=fm->first_frag; (char *)f < (char *)fm->last_frag; f=F_PARALLEL_FRAG_NEXT(f))
269+
if (!frag_is_free(f))
270+
f->statistic_index = core_index;
271+
}
272+
273+
#endif
274+
275+
276+
277+
278+
/* fills a malloc info structure with info about the block
279+
* if a parameter is not supported, it will be filled with 0 */
280+
void parallel_info(struct parallel_block *fm, struct mem_info *info)
281+
{
282+
memset(info,0, sizeof(*info));
283+
/* TODO - Not implemented, need an array here */
284+
return;
285+
}
286+
287+
#endif

0 commit comments

Comments
 (0)