# Usage # $cfabuild/driver/cfa -nodebug -quiet -c -x c /dev/null && rm null.o || echo Need to fix \$cfabuild # make CFABUILD=$cfabuild -j8 # compile # make measurement CFA_APILEVELS=ll OPERATIONS='pta peq pbv' CORPORI='corpus-100-*-1.txt corpus-1-*-1.txt' # append-pbv # make measurement2 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=cfa CFA_SHARINGS=share CORPORI='corpus-1-*-1.txt' # allocate-speed-cfa # make measurement2 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=stl CFA_EXPANSIONS=-1.0 CORPORI='corpus-1-*-1.txt' # allocate-speed-stl # make measurement3 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=cfa CFA_SHARINGS=share CORPORI='corpus-1-*-1.txt' # allocate-space-cfa # make measurement3 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=stl CFA_EXPANSIONS=-1.0 CORPORI='corpus-1-*-1.txt' # allocate-space-stl # make measurement4 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=cfa CFA_EXPANSIONS=0.2 CFA_SHARINGS=share CORPORI='corpus-1-*-1.txt' # allocate-attrib-cfa # make measurement4 CFA_APILEVELS=ll OPERATIONS='pall' PLATFORMS=stl CFA_EXPANSIONS=-1.0 CORPORI='corpus-1-*-1.txt' # allocate-attrib-stl LIBCFA = $(cfabuild)/libcfa/*/src/.libs/libcfa.so CFA = $(cfabuild)/driver/cfa PERFFLAGS_CFA = -nodebug -O2 PERFFLAGS_CXX = -DNDEBUG -O2 -Wl,--no-as-needed -ldl # function: convert to upper case define uc $(shell echo $1 | tr '[:lower:]' '[:upper:]') endef # function: project numbered element of filename named by any-delimited tuple # (call proj,q-w-e-r.txt,-,4) is 4.txt # (call proj,q-w-e-r.foo.txt,.,1) is q-w-e-r define proj $(word $3,$(subst $2, ,$1)) endef # function: project numbered element of filename named by hyphen-delimited tuple # (call hyphProj,q-w-e-r.txt,4) is r.txt define hyphProj $(call proj,$1,-,$2) endef # function: drop file extension and project element # (call bnHyphProj,q-w-e-r.txt,4) is r define bnHyphProj $(call hyphProj,$(basename $1),$2) endef # function: drop file extension, project element and uppercase it # (call ucBnhyphProj,q-w-e-r.txt,4) is R define ucBnHyphProj $(call uc,$(call bnHyphProj,$1,$2)) endef # function: cross two lists, adding given delimiters # (call delCross,+,a b c,1 2) is a+1 a+2 b+1 b+2 c+1 c+2 define delCross $(foreach x,$2,$(foreach xs,$3,$(x)$1$(xs))) endef define delCross3 $(call delCross,$1,$2,$(call delCross,$1,$3,$4)) endef define delCross4 $(call delCross,$1,$2,$(call delCross3,$1,$3,$4,$5)) endef define delCross5 $(call delCross,$1,$2,$(call delCross4,$1,$3,$4,$5,$6)) endef # function: cross two lists, adding hyphen delimiters # (call hyphCross,a b c,1 2) is a-1 a-2 b-1 b-2 c-1 c-2 define hyphCross $(call delCross,-,$1,$2) endef define hyphCross3 $(call delCross3,-,$1,$2,$3) endef define hyphCross4 $(call delCross4,-,$1,$2,$3,$4) endef define hyphCross5 $(call delCross5,-,$1,$2,$3,$4,$5) endef OPERATIONS?=pta peq pbv pall #pno ALLOCS?=reuse fresh CFA_APILEVELS?=hl ll CFA_SHARINGS?=share noshare PLATFORMS?=cfa stl #buhr94 ifneq ($(filter cfa,$(PLATFORMS)),) CFA_APIS=$(call hyphCross,$(CFA_APILEVELS),$(CFA_SHARINGS)) endif ifneq ($(filter stl,$(PLATFORMS)),) STL_APIS=na-na endif ifneq ($(filter buhr94,$(PLATFORMS)),) BUHR94_APIS=na-na endif APIS = $(CFA_APIS) $(STL_APIS) $(BUHR94_APIS) OPERATIONS_USING_ALLOCS=pta peq define enrichOperationsAllocs $(call hyphCross3,$(filter peq pta,$(OPERATIONS)),$1,$(ALLOCS)) $(call hyphCross3,$(filter-out peq pta,$(OPERATIONS)),$1,na) endef CFA_PERFPROGS=$(call hyphCross,perfexp-cfa,$(call enrichOperationsAllocs,$(CFA_APIS))) STL_PERFPROGS=$(call hyphCross,perfexp-stl,$(call enrichOperationsAllocs,$(STL_APIS))) BUHR94_PERFPROGS=$(call hyphCross,perfexp-buhr94,$(call enrichOperationsAllocs,$(BUHR94_APIS))) PERFPROGS = $(CFA_PERFPROGS) $(STL_PERFPROGS) $(BUHR94_PERFPROGS) all : $(PERFPROGS) PP_SPLIT := $(shell echo "${PERFPROGS}" | sed -e 's/ /\\n/g') echoPerfProgs: echo -e '$(PP_SPLIT)' perfexp-%.o: API=$(call ucBnHyphProj,$@,2) perfexp-%.o: OPERATION=$(call ucBnHyphProj,$@,3) perfexp-%.o: CFA_APILEVEL=$(call ucBnHyphProj,$@,4) perfexp-%.o: CFA_SHARING=$(call ucBnHyphProj,$@,5) perfexp-%.o: ALLOC=$(call ucBnHyphProj,$@,6) perfexp-%.o: SCENARIO_SWITCH=-DIMPL_$(API)_$(CFA_APILEVEL)_$(CFA_SHARING) -DOP_$(OPERATION) -DALLOC_$(ALLOC) perfexp-cfa-%.o: CMD=$(CFA) -c $(PERFFLAGS_CFA) $< -o $@ $(SCENARIO_SWITCH) perfexp-stl-%.o: CMD=$(CXX) -c -xc++ $(PERFFLAGS_CXX) $< -o $@ $(SCENARIO_SWITCH) perfexp-buhr94-%.o: CMD=$(CXX) -xc++ -c $(PERFFLAGS_CXX) $< -o $@ $(SCENARIO_SWITCH) perfexp-cfa-peq-%.o: prog.cfa $(LIBCFA) $(CMD) perfexp-cfa-pta-%.o: prog.cfa $(LIBCFA) $(CMD) perfexp-cfa-pbv-%.o: prog-passbyval.cfa $(LIBCFA) $(CMD) perfexp-cfa-pb%.o: prog-passbyX.cfa $(LIBCFA) $(CMD) perfexp-cfa-pfi-%.o: prog-find.cfa $(LIBCFA) $(CMD) perfexp-cfa-pall-%.o: prog-allocn.cfa $(LIBCFA) $(CMD) perfexp-cfa-pno-%.o: prog-normalize.cfa $(LIBCFA) $(CMD) perfexp-stl-peq-%.o: prog.cfa $(CMD) perfexp-stl-pta-%.o: prog.cfa $(CMD) perfexp-stl-pbv-%.o: prog-passbyval.cfa $(CMD) perfexp-stl-pfi-%.o: prog-find.cfa $(CMD) perfexp-stl-pall-%.o: prog-allocn.cfa $(CMD) perfexp-stl-pno-%.o: prog-normalize.cfa $(CMD) perfexp-buhr94-peq-%.o: prog.cfa buhr94-string.o buhr94-VbyteSM.o $(CMD) perfexp-buhr94-pta-%.o: prog.cfa buhr94-string.o buhr94-VbyteSM.o $(CMD) perfexp-buhr94-pta-%.o: prog-passbyval.cfa buhr94-string.o buhr94-VbyteSM.o $(CMD) perfexp-buhr94-pall-%.o: prog-allocn.cfa buhr94-string.o buhr94-VbyteSM.o $(CMD) perfexp-buhr94-pno-%.o: prog-normalize.cfa buhr94-string.o buhr94-VbyteSM.o $(CMD) # one of the pbx cases also needs to link with not_string_res.o (handling manually) perfexp-cfa-%: perfexp-cfa-%.o $(LIBCFA) $(CFA) $(PERFFLAGS_CFA) $< -o $@ perfexp-stl-%: perfexp-stl-%.o $(LIBCFA) $(CFA) $(PERFFLAGS_CFA) $< /lib/x86_64-linux-gnu/libstdc++.so.6 -o $@ perfexp-buhr94-% : perfexp-buhr94-%.o buhr94-string.o buhr94-VbyteSM.o $(CXX) $(PERFFLAGS_CXX) $^ -o $@ buhr94-string.o: $(CXX) -xc++ -c $(PERFFLAGS_CXX) ~/usys1/sm/string/StringSharing/src/string.cc -o $@ buhr94-VbyteSM.o: $(CXX) -xc++ -c $(PERFFLAGS_CXX) ~/usys1/sm/string/StringSharing/src/VbyteSM.cc -o $@ clean: rm -f *.o perfexp* MEASURE = $(PERFPROGS) CORPUS_MEANLEN_MODE?=auto #manual CORPUS_MEANLEN_START?=1 CORPUS_MEANLEN_END?=500 CORPUS_MEANLEN_STEPS_PER_DOUBLE?=1 CORPUS_MEANLEN_MANVALS?=20 50 100 200 500 COPRUS_NSTRSS?=100 CORPUS_RELSCALES?=1.0 CORPUS_SEEDS?=9876 CORPUS_OFFSET_INSTRS?=t0 CORPUS_MEANLENS_AUTO=${shell python3 gen-size-steps.py ${CORPUS_MEANLEN_START} ${CORPUS_MEANLEN_END} ${CORPUS_MEANLEN_STEPS_PER_DOUBLE}} CORPUS_MEANLENS=\ $(if $(filter auto,$(CORPUS_MEANLEN_MODE)),$(CORPUS_MEANLENS_AUTO), \ $(if $(filter manual,$(CORPUS_MEANLEN_MODE)),$(CORPUS_MEANLEN_MANVALS), \ ERROR)) CORPUS_SERIES_IDS=$(call delCross3,+,$(CORPUS_RELSCALES),$(CORPUS_SEEDS),$(CORPUS_OFFSET_INSTRS)) CORPUS_SLUGS=$(call hyphCross4,corpus,$(COPRUS_NSTRSS),$(CORPUS_MEANLENS),$(CORPUS_SERIES_IDS)) CORPORI=$(call delCross,.,$(CORPUS_SLUGS),txt) # function to interpret an offset instruction for a given mean-length, # producing the pair of arguments for locn and offset # # An offset instruction is an opcode and natural-number argument. # The opcode is either (t)ake or (l)eave. # The argument is how much length to take from / leave behind. # The resulting amount is deducted from the mean-length and returned in offset. # The remaining mean-length is returned in locn. # # $(call interpOffsetInstr,20,l1) = 1 19 (i.e. constant-length 20) # $(call interpOffsetInstr,20,l5) = 5 15 # $(call interpOffsetInstr,20,t5) = 15 5 # $(call interpOffsetInstr,20,t0) = 20 0 (i.e. full variability) define interpOffsetInstr $(strip $(eval qty := $(subst t,,$(subst l,,$2))) $(if $(filter t%,$2), $(shell expr $1 - $(qty)) $(qty), $(if $(filter l%,$2), $(qty) $(shell expr $1 - $(qty)), ERROR)) ) endef corpori: $(CORPORI) make-corpus: make-corpus.cfa $(CFA) $< -o $@ corpus-%.txt: COPRUS_NSTRS=$(call bnHyphProj,$@,2) corpus-%.txt: CORPUS_MEANLEN=$(call bnHyphProj,$@,3) corpus-%.txt: CORPUS_SERIES_ID=$(call bnHyphProj,$@,4) corpus-%.txt: CORPUS_RELSCALE=$(call proj,$(CORPUS_SERIES_ID),+,1) corpus-%.txt: CORPUS_SEED=$(call proj,$(CORPUS_SERIES_ID),+,2) corpus-%.txt: CORPUS_OFFSET_INSTR=$(call proj,$(CORPUS_SERIES_ID),+,3) corpus-%.txt: make-corpus $(eval CORPUS_OFFSET_INTERPD := $(call interpOffsetInstr,$(CORPUS_MEANLEN),$(CORPUS_OFFSET_INSTR))) $(eval CORPUS_LOCN := $(word 1,$(CORPUS_OFFSET_INTERPD))) $(eval CORPUS_OFFSET := $(word 2,$(CORPUS_OFFSET_INTERPD))) ./$< $(COPRUS_NSTRS) $(CORPUS_LOCN) $(CORPUS_RELSCALE) $(CORPUS_SEED) $(CORPUS_OFFSET) > $@ RUN_TASKSET_CPULIST=6 # both ?= and := ifeq ($(origin MEASUREMENT_TOFILE), undefined) MEASUREMENT_TOFILE:=measurement-$(shell date '+%F--%H-%M-%S').output endif # General timing # Output file gets concatenation of program outputs (one line per run) measurement: $(MEASURE) corpori @echo "running $(words $(MEASURE)) programs:" $(MEASURE) @echo "... on $(words $(CORPORI)) corpori:" $(CORPORI) @echo "... for $(shell expr $(words $(MEASURE)) "*" $(words $(CORPORI))) rows into:" $(MEASUREMENT_TOFILE) @for prog in $(MEASURE) ; do \ for corpus in $(CORPORI) ; do \ corpusbody=`cat $$corpus` ; \ resulttext=`taskset --cpu-list $(RUN_TASKSET_CPULIST) ./$$prog 100 10 $$corpusbody` ; \ echo $$prog,$$corpus,$$resulttext >> $(MEASUREMENT_TOFILE) ; \ echo $$prog,$$corpus,$$resulttext ; \ done ; \ done CFA_EXPANSIONS?=0.02 0.05 0.1 0.2 0.4 0.5 0.9 0.98 # Special-case timing with extra IV for CFA_EXPANSIONS # Output file gets concatenation of program outputs (one line per run) measurement2: $(MEASURE) corpori @echo "running $(words $(MEASURE)) programs:" $(MEASURE) @echo "... on $(words $(CORPORI)) corpori:" $(CORPORI) @echo "... with $(words $(CFA_EXPANSIONS)) expansions:" $(CFA_EXPANSIONS) @echo "... for $(shell expr $(words $(MEASURE)) "*" $(words $(CORPORI)) "*" $(words $(CFA_EXPANSIONS))) rows into:" $(MEASUREMENT_TOFILE) @for prog in $(MEASURE) ; do \ for corpus in $(CORPORI) ; do \ for expansion in $(CFA_EXPANSIONS) ; do \ corpusbody=`cat $$corpus` ; \ printed=`taskset --cpu-list $(RUN_TASKSET_CPULIST) ./$$prog 1000 1.006 $$expansion 10 $$corpusbody` ; \ echo $$prog,$$corpus,$$expansion,$$printed >> $(MEASUREMENT_TOFILE) ; \ echo $$prog,$$corpus,$$expansion,$$printed ; \ done ; \ done ; \ done # Space, with the IV for CFA_EXPANSIONS # Runs Mubeen's malloc interceptor to get malloc-request stats # Output file gets concatenation of the interceptor's output (one line per run); program's output ignorred # Expect and ignore crashes; they're during shutdown, after everything we care about is over measurement3: $(MEASURE) corpori @echo "running $(words $(MEASURE)) programs:" $(MEASURE) @echo "... on $(words $(CORPORI)) corpori:" $(CORPORI) @echo "... with $(words $(CFA_EXPANSIONS)) expansions:" $(CFA_EXPANSIONS) @echo "... for $(shell expr $(words $(MEASURE)) "*" $(words $(CORPORI))) rows into:" $(MEASUREMENT_TOFILE) @for prog in $(MEASURE) ; do \ for corpus in $(CORPORI) ; do \ for expansion in $(CFA_EXPANSIONS) ; do \ corpusbody=`cat $$corpus` ; \ LD_PRELOAD=~/plg2/mubeen-stat-shim/malloc/mallocWrappers.so ./$$prog 1000 1.006 $$expansion 10 $$corpusbody ; \ printed=`tail -n 1 preload_dump.txt` ; \ echo $$prog $$corpus $$expansion $$printed >> $(MEASUREMENT_TOFILE) ; \ echo $$prog $$corpus $$expansion $$printed ; \ rm preload_dump.txt ; \ done ; \ done ; \ done # Time attribution, with the IV for CFA_EXPANSIONS # Runs the SUT under perf, then crunches the perf result # Output file gets concatenation of perf summaries (several lines per run); program's output ignorred # Expect and ignore output "addr2line: DWARF error: section .debug_info is larger than its filesize!" measurement4: $(MEASURE) corpori @echo "running $(words $(MEASURE)) programs:" $(MEASURE) @echo "... on $(words $(CORPORI)) corpori:" $(CORPORI) @echo "... with $(words $(CFA_EXPANSIONS)) expansions:" $(CFA_EXPANSIONS) @echo "... for $(shell expr $(words $(MEASURE)) "*" $(words $(CORPORI))) rows into:" $(MEASUREMENT_TOFILE) @RUNID=`date '+%F--%H-%M-%S'` ; \ for prog in $(MEASURE) ; do \ for corpus in $(CORPORI) ; do \ for expansion in $(CFA_EXPANSIONS) ; do \ SLUG=measurement--$$prog--$$corpus--$$expansion--$$RUNID ; \ corpusbody=`cat $$corpus` ; \ perf record --call-graph dwarf -m16M ./$$prog 1000 1.006 $$expansion 10 $$corpusbody ; \ mv perf.data $$SLUG.data ; \ perf script -i $$SLUG.data > $$SLUG.perf ; \ ~/flamegraph/FlameGraph/stackcollapse-perf.pl $$SLUG.perf > $$SLUG.folded ; \ ~/flamegraph/FlameGraph/flamegraph.pl $$SLUG.folded > $$SLUG.svg ; \ python3 process-allocn-attrib.py $$SLUG.folded | xargs -L1 echo $$prog $$corpus $$expansion >> $(MEASUREMENT_TOFILE) ; \ done ; \ done ; \ done # # Experiment-specific "summary" targets # # These all use recursive make invocations, after setting the scoping variables. # Recursive invocation necessary to recompute dependencies like corpori -> $(CORPORI). # In the top-level make, the extent of the dependency is computed upfront, using # default values, overridden by CLI-provided values. # Setting the value per-target makes it available to other targets' bodies, but it # does not affect the previously-computed dependencies. # Exporting the values and working through a child make has the child intialize its # dependencies using the summary-target-provided values. # For that to work, the exported variable default values given above must use ?=. .PHONY: result-append-pbv.csv result-allocate-speed-%.csv result-allocate-speed-cfa.csv export OPERATIONS export ALLOCS export CFA_APILEVELS export CFA_SHARINGS export PLATFORMS export CFA_EXPANSIONS export CORPUS_MEANLEN_MODE export CORPUS_MEANLEN_START export CORPUS_MEANLEN_END export CORPUS_MEANLEN_STEPS_PER_DOUBLE export CORPUS_MEANLEN_MANVALS export COPRUS_NSTRSS export CORPUS_RELSCALES export CORPUS_SEEDS export CORPUS_OFFSET_INSTRS export MEASUREMENT_TOFILE result-ANY: $(MAKE) $(SUBTARGET) result-append-pbv.csv: CFA_APILEVELS=ll result-append-pbv.csv: OPERATIONS=pta peq pbv result-append-pbv.csv: CORPUS_OFFSET_INSTRS=t0 l1 result-append-pbv.csv: CORPUS_MEANLEN_STEPS_PER_DOUBLE=4 result-append-pbv.csv: CORPUS_SEEDS=501 502 result-append-pbv.csv: SUBTARGET=measurement result-append-pbv.csv: result-ANY cp $(MEASUREMENT_TOFILE) $@ result-allocate-ANY: OPERATIONS=pall result-allocate-ANY: CORPUS_OFFSET_INSTRS=l15 result-allocate-ANY: CORPUS_MEANLEN_MODE=manual result-allocate-ANY: CFA_SHARINGS=share result-allocate-ANY: CORPUS_SEEDS=101 102 103 104 105 result-allocate-ANY: CFA_APILEVELS=ll result-allocate-ANY: result-ANY result-allocate-ANY-cfa: PLATFORMS=cfa result-allocate-ANY-cfa: result-allocate-ANY result-allocate-ANY-stl: PLATFORMS=stl result-allocate-ANY-stl: CFA_EXPANSIONS=-1.0 result-allocate-ANY-stl: result-allocate-ANY result-allocate-speed-cfa.csv: SUBTARGET=measurement2 result-allocate-speed-cfa.csv: result-allocate-ANY-cfa cp $(MEASUREMENT_TOFILE) $@ result-allocate-speed-stl.csv: SUBTARGET=measurement2 result-allocate-speed-stl.csv: result-allocate-ANY-stl cp $(MEASUREMENT_TOFILE) $@ # result-allocate-space-cfa.ssv: SUBTARGET=measurement3 # result-allocate-space-cfa.ssv: result-allocate-ANY-cfa # cp $(MEASUREMENT_TOFILE) $@ # result-allocate-space-stl.ssv: SUBTARGET=measurement3 # result-allocate-space-stl.ssv: result-allocate-ANY-stl # cp $(MEASUREMENT_TOFILE) $@ # result-allocate-attrib-cfa.ssv: SUBTARGET=measurement4 # result-allocate-attrib-cfa.ssv: result-allocate-ANY-cfa # cp $(MEASUREMENT_TOFILE) $@ # result-allocate-attrib-stl.ssv: SUBTARGET=measurement4 # result-allocate-attrib-stl.ssv: result-allocate-ANY-stl # cp $(MEASUREMENT_TOFILE) $@ # result-allocate-speed-%.csv: SUBTARGET=measurement2 # result-allocate-speed-%.csv: result-allocate-ANY-% # cp $(MEASUREMENT_TOFILE) $@ result-allocate-space-%.ssv: SUBTARGET=measurement3 result-allocate-space-%.ssv: result-allocate-ANY-% cp $(MEASUREMENT_TOFILE) $@ result-allocate-attrib-%.ssv: SUBTARGET=measurement4 result-allocate-attrib-%.ssv: result-allocate-ANY-% cp $(MEASUREMENT_TOFILE) $@ # .PHONY result-append-pbv.csv result-allocate-ANY-cfa result-allocate-speed-stl.csv # result-allocate-space-cfa.csv # result-allocate-space-stl.csv # result-allocate-attrib-cfa.csv # result-allocate-attrib-stl.csv