File: check-memory

package info (click to toggle)
unison-2.53 2.53.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,876 kB
  • sloc: ml: 38,891; objc: 3,577; ansic: 3,122; python: 430; makefile: 223; sh: 205
file content (213 lines) | stat: -rwxr-xr-x 5,230 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/bin/sh

# NB: This program is a work in progress.

# This program invokes unison in varying ways to attempt to determine
# how much memory is required for a given sync, or alternatively how
# big a sync can be done in a given amount of memory.

# The program expects to own $HOME/UNISON-TEST, but tries not to
# damage any files existing when it is run.

# This program is written in POSIX /bin/sh and intends to use only
# tools specified by POSIX, specifically avoiding bash and GNU/Linux
# extensions not present on other systems.  Practically, for now, it
# will use a subset that is present on GNU/Linux, macOS, *BSD, and
# illumos, documented here.
#   - seq(1)

# The overall design is
#  - a number of shell functions for various setup and micro tests
#  - functions to wrap those in loops
#  - functions to format output
#  - written (for now) for nerds; errors understandable from reading
#    the sources are good enough

# The sh style is
#   quote when necessary
#   avoid quotes when static analysis says that is safe
#   use ${var} always

# TODO
#   - figure out how to set limits on remote process
#   - figure out how to set UNISON for remote process
#   - loop over sizes

log () {
    now=`date +%s`
    echo "check-memory: $now $*"
}

fatal () {
    log FATAL $*
    exit 1
}

CONTAINER=/tmp
DIR=${CONTAINER}/UNISON-TEST

goto_dir () {
    cd ${CONTAINER}
    if [ \! -d ${DIR} ]; then
	mkdir ${DIR} || fatal mkdir
    fi
    cd ${DIR} || fatal cd

    # Ensure no other uid can access the socket.
    chmod 700 . || fatal chmod

    if [ -e local -o -e remote ]; then
	fatal source or remote exists at startup
    fi

    # Avoid creating archive files in the user's directory.
    # Ensure that tests start out without leftover state.
    UNISON=${DIR}/.unison.local
    export UNISON
    if [ -e .unison ]; then
	fatal .unison exists at startup
    fi
}

# Clean up all state we created.
fini () {
    # Be extra careful about removals.
    if [ -d ../UNISON-TEST ]; then
	rm -rf local remote .unison.local .unison.remote s
    else
	fatal fini not in UNISON-TEST
    fi
}

# Create N*M small files.
init_N_M () {
    if [ -e local ]; then
	fatal init_N_m local exists
    fi
    mkdir local

    for n in $(seq $1); do
	mkdir local/$n
	for m in $(seq $2); do
	    echo $n $m > local/$n/$m
	done
    done
}

touch_N_M_all () {
    if [ ! -e local ]; then
	fatal touch_N_m local does not exist
    fi

    find local -type f | while read f; do
	date >> $f
    done
}

# Set limit of arg1 to arg2.
# POSIX defines very little:
#   https://pubs.opengroup.org/onlinepubs/9799919799/
# and in particular does not define:
#   -m -v
#
# POSIX defines setrlimit(2):
#   https://pubs.opengroup.org/onlinepubs/9799919799/functions/getrlimit.html
#
# Generally, m (not POSIX) corresponds to RLIMIT_RSS (not POSIX) and v
# (not POSIX) corresponds to RLIMIT_AS (POSIX).
#
# With -v/RLIMIT_AS, address space, not memory usage, is limited, and
# thus there is a larger base load of VA surely not backed by pages.
#
# On older macOS, "d" and "m" do not seem to limit malloc.
# On NetBSD 10, "d" and "m" do not limit malloc.
#   v limits address space, with background usage higher than one
#   would guess.  Also, v limits are not repeatable.
# On Debian 12, "d" limits malloc and "m" does not.
#
limit () {
    flag=-"$1"
    log limit flag $flag
    old=`ulimit $flag`
    ulimit $flag $2
    new=`ulimit $flag`

    log limit flag $flag old $old req $2 new $new
}

limit_display () {
    log SOFT
    ulimit -S -a
    if false; then
	log HARD
	ulimit -H -a
    fi
}

start_server () {
    UNISON=${DIR}/.unison.remote
    export UNISON

    unison -socket s $* &
    sleep 1
}

# Perform a sync
#  expect: local and remote already set up
#  results: exit status stored in STATUS
do_sync () {
    unison -killserver -batch $* local socket://{${DIR}/s}//${DIR}/remote
    STATUS=$?
}

# For no good reason, pick 10x1000 = 10^4 files.
# Use the same memory limit for local and remote.  The search space is
# too large, and finding the level at which one breaks is, for now,
# good enough.
# \todo Expand to take args, so it can be used in a loop.
simple_test () {
    N=10
    M=1000

    # NetBSD 10 amd64 10 1000: 1373 bad 1376 ok
    # NetBSD 10 amd64 20 1000: 1376 ok
    # NetBSD 10 amd64 40 1000: 1376 ok
    memory=1376
    # NetBSD 10 amd64 10 1000: 84 bad 88 ok
    # NetBSD 10 amd64 20 1000: 124 bad 128 ok
    # NetBSD 10 amd64 40 1000: 208 bad 212 ok
    stack=88

    # Create many files, N dirs of M files.
    init_N_M ${N} ${M}

    # Set limits.  Set both d and m, because of surprising and not yet
    # understood test results.
    limit d ${memory}
    limit m ${memory}
    limit s ${stack}
    limit_display

    start_server -ignorearchives
    do_sync -ignorearchives
    # log a cryptic line, that can be grepped for and parsed programmatically
    log "sync ${N} ${M} ${memory} ${stack} ${STATUS}"

    touch_N_M_all
    start_server
    do_sync
    log "sync-touch-all ${N} ${M} ${memory} ${stack} ${STATUS}"
}

# \todo Write a loop with binary search, to find the memory needed for a given test.
# \todo Write a loop over test sizes.

all () {
    goto_dir

    simple_test

    fini
}

all