From 94ffdcceb38b6202e912e3df512f8fcf4d085a49 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Wed, 29 May 2024 15:48:00 -0400 Subject: [PATCH 1/4] Add fsm_vacuum, which reduces the state array when over-allocated. --- include/fsm/fsm.h | 9 +++++++++ src/libfsm/Makefile | 1 + src/libfsm/fsm.c | 2 +- src/libfsm/internal.h | 3 +++ src/libfsm/libfsm.syms | 1 + src/libfsm/vacuum.c | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/libfsm/vacuum.c diff --git a/include/fsm/fsm.h b/include/fsm/fsm.h index 2b4c438f1..a5e6ef388 100644 --- a/include/fsm/fsm.h +++ b/include/fsm/fsm.h @@ -493,5 +493,14 @@ int fsm_fgetc(void *opaque); /* expects opaque to be FILE * */ int fsm_shuffle(struct fsm *fsm, unsigned seed); +/* Attempt to reclaim memory if an FSM has significantly reduced its + * state count. Returns 1 if */ +enum fsm_vacuum_res { + FSM_VACUUM_NO_CHANGE, + FSM_VACUUM_REDUCED_MEMORY, + FSM_VACUUM_ERROC_REALLOC = -1, +} +fsm_vacuum(struct fsm *fsm); + #endif diff --git a/src/libfsm/Makefile b/src/libfsm/Makefile index 005f7d4c6..2b7aba005 100644 --- a/src/libfsm/Makefile +++ b/src/libfsm/Makefile @@ -22,6 +22,7 @@ SRC += src/libfsm/trim.c SRC += src/libfsm/example.c SRC += src/libfsm/getc.c SRC += src/libfsm/shuffle.c +SRC += src/libfsm/vacuum.c SRC += src/libfsm/vm.c # graph things diff --git a/src/libfsm/fsm.c b/src/libfsm/fsm.c index 6a7bb790f..b9f092973 100644 --- a/src/libfsm/fsm.c +++ b/src/libfsm/fsm.c @@ -57,7 +57,7 @@ fsm_new(const struct fsm_options *opt) return NULL; } - new->statealloc = 128; /* guess */ + new->statealloc = FSM_DEFAULT_STATEALLOC; new->statecount = 0; new->endcount = 0; new->capture_info = NULL; diff --git a/src/libfsm/internal.h b/src/libfsm/internal.h index 6e77510a7..024bf99df 100644 --- a/src/libfsm/internal.h +++ b/src/libfsm/internal.h @@ -44,6 +44,9 @@ struct state_array; #define FSM_CAPTURE_MAX INT_MAX +/* guess for default state allocation */ +#define FSM_DEFAULT_STATEALLOC 128 + struct fsm_edge { fsm_state_t state; /* destination */ unsigned char symbol; diff --git a/src/libfsm/libfsm.syms b/src/libfsm/libfsm.syms index f905e1f04..6e1f72dbe 100644 --- a/src/libfsm/libfsm.syms +++ b/src/libfsm/libfsm.syms @@ -68,6 +68,7 @@ fsm_addstate fsm_addstate_bulk fsm_removestate fsm_shuffle +fsm_vacuum fsm_addedge_any fsm_addedge_epsilon diff --git a/src/libfsm/vacuum.c b/src/libfsm/vacuum.c new file mode 100644 index 000000000..2c349c210 --- /dev/null +++ b/src/libfsm/vacuum.c @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Scott Vokes + * + * See LICENCE for the full copyright terms. + */ + +#include +#include +#include + +#include + +#include "internal.h" + +enum fsm_vacuum_res +fsm_vacuum(struct fsm *fsm) +{ + assert(fsm != NULL); + assert(fsm->statecount <= fsm->statealloc); + size_t nceil = fsm->statealloc; + + while ((fsm->statecount < nceil/2) && nceil > 1) { + nceil /= 2; + } + + if (nceil == fsm->statealloc) { + return FSM_VACUUM_NO_CHANGE; + } + + struct fsm_state *nstates = f_realloc(fsm->opt->alloc, + fsm->states, nceil * sizeof(nstates[0])); + if (nstates == NULL) { + return FSM_VACUUM_ERROC_REALLOC; + } + + fsm->states = nstates; + fsm->statealloc = nceil; + + return FSM_VACUUM_REDUCED_MEMORY; +} From 3435f508afe08c606e700d9ddc48efe58d449d74 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Thu, 30 May 2024 08:49:21 -0400 Subject: [PATCH 2/4] Move `FSM_DEFAULT_STATEALLOC` to fsm.c. --- src/libfsm/fsm.c | 3 +++ src/libfsm/internal.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libfsm/fsm.c b/src/libfsm/fsm.c index b9f092973..d027825ff 100644 --- a/src/libfsm/fsm.c +++ b/src/libfsm/fsm.c @@ -22,6 +22,9 @@ #include "capture.h" #include "endids.h" +/* guess for default state allocation */ +#define FSM_DEFAULT_STATEALLOC 128 + void free_contents(struct fsm *fsm) { diff --git a/src/libfsm/internal.h b/src/libfsm/internal.h index 024bf99df..6e77510a7 100644 --- a/src/libfsm/internal.h +++ b/src/libfsm/internal.h @@ -44,9 +44,6 @@ struct state_array; #define FSM_CAPTURE_MAX INT_MAX -/* guess for default state allocation */ -#define FSM_DEFAULT_STATEALLOC 128 - struct fsm_edge { fsm_state_t state; /* destination */ unsigned char symbol; From 8feff1405390e05dc099a41233c2ad095096e49f Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Thu, 30 May 2024 11:24:02 -0400 Subject: [PATCH 3/4] fsm_vacuum: Change return type to bool. --- include/fsm/fsm.h | 11 +++++------ src/libfsm/vacuum.c | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/fsm/fsm.h b/include/fsm/fsm.h index a5e6ef388..1904814bd 100644 --- a/include/fsm/fsm.h +++ b/include/fsm/fsm.h @@ -15,6 +15,8 @@ * be atomic. */ +#include + struct fsm; struct fsm_options; struct path; /* XXX */ @@ -494,12 +496,9 @@ int fsm_shuffle(struct fsm *fsm, unsigned seed); /* Attempt to reclaim memory if an FSM has significantly reduced its - * state count. Returns 1 if */ -enum fsm_vacuum_res { - FSM_VACUUM_NO_CHANGE, - FSM_VACUUM_REDUCED_MEMORY, - FSM_VACUUM_ERROC_REALLOC = -1, -} + * state count. Returns true if the vacuuming attempt succeeded (including + * deciding not to do anything), false if realloc failed. */ +bool fsm_vacuum(struct fsm *fsm); #endif diff --git a/src/libfsm/vacuum.c b/src/libfsm/vacuum.c index 2c349c210..abecf6301 100644 --- a/src/libfsm/vacuum.c +++ b/src/libfsm/vacuum.c @@ -12,7 +12,7 @@ #include "internal.h" -enum fsm_vacuum_res +bool fsm_vacuum(struct fsm *fsm) { assert(fsm != NULL); @@ -24,17 +24,17 @@ fsm_vacuum(struct fsm *fsm) } if (nceil == fsm->statealloc) { - return FSM_VACUUM_NO_CHANGE; + return true; } struct fsm_state *nstates = f_realloc(fsm->opt->alloc, fsm->states, nceil * sizeof(nstates[0])); if (nstates == NULL) { - return FSM_VACUUM_ERROC_REALLOC; + return false; } fsm->states = nstates; fsm->statealloc = nceil; - return FSM_VACUUM_REDUCED_MEMORY; + return true; } From 61478603941bba05a8d42644a518590b67e0e726 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Thu, 30 May 2024 11:29:00 -0400 Subject: [PATCH 4/4] Call fsm_vacuum at the end of fsm_minimise. This also means that many existing tests will exercise fsm_vacuum. --- src/libfsm/minimise.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libfsm/minimise.c b/src/libfsm/minimise.c index 96d92b4e8..94dfdf80b 100644 --- a/src/libfsm/minimise.c +++ b/src/libfsm/minimise.c @@ -157,6 +157,12 @@ fsm_minimise(struct fsm *fsm) fsm_move(fsm, dst); + /* The FSM state count should be settled now, so if the state + * allocation is unnecessarily large move to a smaller one. */ + if (!fsm_vacuum(fsm)) { /* realloc failure */ + r = 0; + } + cleanup: if (mapping != NULL) { f_free(fsm->opt->alloc, mapping);