centralized performance resources

This commit is contained in:
Barrett Ruth 2026-01-10 12:21:52 -05:00
commit 50b15a1522
63 changed files with 328466 additions and 0 deletions

BIN
ocw/1/assignment.pdf Normal file

Binary file not shown.

31
ocw/1/c-primer/Makefile Normal file
View file

@ -0,0 +1,31 @@
CC := clang
ifeq ($(DEBUG),1)
CFLAGS := -Wall -O0 -g
else
CFLAGS := -Wall -O1 -DNDEBUG
endif
LDFLAGS := -lrt -flto -fuse-ld=gold
all: sizes pointer swap
sizes.o: sizes.c
$(CC) $(CFLAGS) -c sizes.c
sizes: sizes.o
$(CC) -o sizes sizes.o $(LDFLAGS)
pointer.o: pointer.c
$(CC) $(CFLAGS) -c pointer.c
pointer: pointer.o
$(CC) -o pointer pointer.o $(LDFLAGS)
swap.o: swap.c
$(CC) $(CFLAGS) -c swap.c
swap: swap.o
$(CC) -o swap swap.o $(LDFLAGS)
clean:
rm -f sizes pointer swap *.o *.gcda *.gcno *.gcov perf.data */perf.data cachegrind.out.*

47
ocw/1/c-primer/pointer.c Normal file
View file

@ -0,0 +1,47 @@
// Copyright (c) 2012 MIT License by 6.172 Staff
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char * argv[]) { // What is the type of argv?
int i = 5;
// The & operator here gets the address of i and stores it into pi
int * pi = &i;
// The * operator here dereferences pi and stores the value -- 5 --
// into j.
int j = *pi;
char c[] = "6.172";
char * pc = c; // Valid assignment: c acts like a pointer to c[0] here.
char d = *pc;
printf("char d = %c\n", d); // What does this print?
// compound types are read right to left in C.
// pcp is a pointer to a pointer to a char, meaning that
// pcp stores the address of a char pointer.
char ** pcp;
pcp = argv; // Why is this assignment valid?
const char * pcc = c; // pcc is a pointer to char constant
char const * pcc2 = c; // What is the type of pcc2?
// For each of the following, why is the assignment:
*pcc = '7'; // invalid?
pcc = *pcp; // valid?
pcc = argv[0]; // valid?
char * const cp = c; // cp is a const pointer to char
// For each of the following, why is the assignment:
cp = *pcp; // invalid?
cp = *argv; // invalid?
*cp = '!'; // valid?
const char * const cpc = c; // cpc is a const pointer to char const
// For each of the following, why is the assignment:
cpc = *pcp; // invalid?
cpc = argv[0]; // invalid?
*cpc = '@'; // invalid?
return 0;
}

View file

@ -0,0 +1,21 @@
// Copyright (c) 2012 MIT License by 6.172 Staff
// All occurences of ONE will be replaced by 1.
#define ONE 1
// Macros can also behave similar to inline functions.
// Note that parentheses around arguments are required to preserve order of
// operations. Otherwise, you can introduce bugs when substitution happens
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int c = ONE, d = ONE + 5;
int e = MIN(c, d);
#ifndef NDEBUG
// This code will be compiled only when
// the macro NDEBUG is not defined.
// Recall that if clang is passed -DNDEBUG on the command line,
// then NDEBUG will be defined.
if (something) {}
#endif

14
ocw/1/c-primer/sizes.c Normal file
View file

@ -0,0 +1,14 @@
// Copyright (c) 2012 MIT License by 6.172 Staff
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void subprocedure(int x, int y) {
int z = x + y;
}
int main() {
int x = 3, y = 5;
subprocedure(x, y);
}

476
ocw/1/c-primer/sizes.s Normal file
View file

@ -0,0 +1,476 @@
.file "sizes.c"
.text
.Ltext0:
.file 0 "/home/frozen/dev/performance-engineering-ocw/1/c-primer" "sizes.c"
.section .rodata
.LC0:
.string "size of int : %zu bytes \n"
.LC1:
.string "size of you : %zu bytes \n"
.text
.globl main
.type main, @function
main:
.LFB6:
.file 1 "sizes.c"
.loc 1 9 12
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $48, %rsp
.loc 1 9 12
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
.loc 1 18 3
leaq .LC0(%rip), %rax
movl $4, %esi
movq %rax, %rdi
movl $0, %eax
call printf@PLT
.loc 1 35 10
movl $12345, -40(%rbp)
.loc 1 36 12
movl $4, -36(%rbp)
.loc 1 43 3
leaq .LC1(%rip), %rax
movl $8, %esi
movq %rax, %rdi
movl $0, %eax
call printf@PLT
.loc 1 45 10
movl $0, %eax
.loc 1 46 1
movq -8(%rbp), %rdx
subq %fs:40, %rdx
je .L3
call __stack_chk_fail@PLT
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size main, .-main
.Letext0:
.file 2 "/usr/include/stdio.h"
.section .debug_info,"",@progbits
.Ldebug_info0:
.long 0x118
.value 0x5
.byte 0x1
.byte 0x8
.long .Ldebug_abbrev0
.uleb128 0x3
.long .LASF13
.byte 0x1d
.byte 0x3
.long 0x31647
.long .LASF0
.long .LASF1
.quad .Ltext0
.quad .Letext0-.Ltext0
.long .Ldebug_line0
.uleb128 0x1
.byte 0x8
.byte 0x7
.long .LASF2
.uleb128 0x1
.byte 0x4
.byte 0x7
.long .LASF3
.uleb128 0x1
.byte 0x1
.byte 0x8
.long .LASF4
.uleb128 0x1
.byte 0x2
.byte 0x7
.long .LASF5
.uleb128 0x1
.byte 0x1
.byte 0x6
.long .LASF6
.uleb128 0x1
.byte 0x2
.byte 0x5
.long .LASF7
.uleb128 0x4
.byte 0x4
.byte 0x5
.string "int"
.uleb128 0x1
.byte 0x8
.byte 0x5
.long .LASF8
.uleb128 0x1
.byte 0x1
.byte 0x6
.long .LASF9
.uleb128 0x5
.long 0x6b
.uleb128 0x6
.byte 0x8
.long 0x72
.uleb128 0x1
.byte 0x8
.byte 0x5
.long .LASF10
.uleb128 0x1
.byte 0x8
.byte 0x7
.long .LASF11
.uleb128 0x7
.long .LASF14
.byte 0x2
.value 0x16b
.byte 0xc
.long 0x5d
.long 0xa3
.uleb128 0x8
.long 0x77
.uleb128 0x9
.byte 0
.uleb128 0xa
.long .LASF15
.byte 0x1
.byte 0x9
.byte 0x5
.long 0x5d
.quad .LFB6
.quad .LFE6-.LFB6
.uleb128 0x1
.byte 0x9c
.long 0x10f
.uleb128 0xb
.byte 0x8
.byte 0x1
.byte 0x1d
.byte 0xb
.long 0xe8
.uleb128 0xc
.string "id"
.byte 0x1
.byte 0x1e
.byte 0x9
.long 0x5d
.byte 0
.uleb128 0xd
.long .LASF12
.byte 0x1
.byte 0x1f
.byte 0x9
.long 0x5d
.byte 0x4
.byte 0
.uleb128 0xe
.long .LASF16
.byte 0x1
.byte 0x20
.byte 0x5
.long 0xc5
.uleb128 0x2
.string "you"
.byte 0x22
.byte 0xb
.long 0xe8
.uleb128 0x2
.byte 0x91
.sleb128 -56
.uleb128 0x2
.string "x"
.byte 0x28
.byte 0x7
.long 0x10f
.uleb128 0x2
.byte 0x91
.sleb128 -48
.byte 0
.uleb128 0xf
.long 0x5d
.uleb128 0x10
.long 0x33
.byte 0x4
.byte 0
.byte 0
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.uleb128 0x1
.uleb128 0x24
.byte 0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.uleb128 0x3
.uleb128 0xe
.byte 0
.byte 0
.uleb128 0x2
.uleb128 0x34
.byte 0
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0x21
.sleb128 1
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x2
.uleb128 0x18
.byte 0
.byte 0
.uleb128 0x3
.uleb128 0x11
.byte 0x1
.uleb128 0x25
.uleb128 0xe
.uleb128 0x13
.uleb128 0xb
.uleb128 0x90
.uleb128 0xb
.uleb128 0x91
.uleb128 0x6
.uleb128 0x3
.uleb128 0x1f
.uleb128 0x1b
.uleb128 0x1f
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x10
.uleb128 0x17
.byte 0
.byte 0
.uleb128 0x4
.uleb128 0x24
.byte 0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.byte 0
.byte 0
.uleb128 0x5
.uleb128 0x26
.byte 0
.uleb128 0x49
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0x6
.uleb128 0xf
.byte 0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0x7
.uleb128 0x2e
.byte 0x1
.uleb128 0x3f
.uleb128 0x19
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0x5
.uleb128 0x39
.uleb128 0xb
.uleb128 0x27
.uleb128 0x19
.uleb128 0x49
.uleb128 0x13
.uleb128 0x3c
.uleb128 0x19
.uleb128 0x1
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0x8
.uleb128 0x5
.byte 0
.uleb128 0x49
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0x9
.uleb128 0x18
.byte 0
.byte 0
.byte 0
.uleb128 0xa
.uleb128 0x2e
.byte 0x1
.uleb128 0x3f
.uleb128 0x19
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x27
.uleb128 0x19
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x40
.uleb128 0x18
.uleb128 0x7c
.uleb128 0x19
.uleb128 0x1
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0xb
.uleb128 0x13
.byte 0x1
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x1
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0xc
.uleb128 0xd
.byte 0
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x38
.uleb128 0xb
.byte 0
.byte 0
.uleb128 0xd
.uleb128 0xd
.byte 0
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x38
.uleb128 0xb
.byte 0
.byte 0
.uleb128 0xe
.uleb128 0x16
.byte 0
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0xf
.uleb128 0x1
.byte 0x1
.uleb128 0x49
.uleb128 0x13
.byte 0
.byte 0
.uleb128 0x10
.uleb128 0x21
.byte 0
.uleb128 0x49
.uleb128 0x13
.uleb128 0x2f
.uleb128 0xb
.byte 0
.byte 0
.byte 0
.section .debug_aranges,"",@progbits
.long 0x2c
.value 0x2
.long .Ldebug_info0
.byte 0x8
.byte 0
.value 0
.value 0
.quad .Ltext0
.quad .Letext0-.Ltext0
.quad 0
.quad 0
.section .debug_line,"",@progbits
.Ldebug_line0:
.section .debug_str,"MS",@progbits,1
.LASF10:
.string "long long int"
.LASF3:
.string "unsigned int"
.LASF15:
.string "main"
.LASF13:
.string "GNU C23 15.1.1 20250425 -mtune=generic -march=x86-64 -g -O0"
.LASF2:
.string "long unsigned int"
.LASF11:
.string "long long unsigned int"
.LASF4:
.string "unsigned char"
.LASF9:
.string "char"
.LASF8:
.string "long int"
.LASF16:
.string "student"
.LASF12:
.string "year"
.LASF5:
.string "short unsigned int"
.LASF14:
.string "printf"
.LASF7:
.string "short int"
.LASF6:
.string "signed char"
.section .debug_line_str,"MS",@progbits,1
.LASF0:
.string "sizes.c"
.LASF1:
.string "/home/frozen/dev/performance-engineering-ocw/1/c-primer"
.ident "GCC: (GNU) 15.1.1 20250425"
.section .note.GNU-stack,"",@progbits

21
ocw/1/c-primer/swap.c Normal file
View file

@ -0,0 +1,21 @@
// Copyright (c) 2012 MIT License by 6.172 Staff
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void swap(int i, int j) {
int temp = i;
i = j;
j = temp;
}
int main() {
int k = 1;
int m = 2;
swap(k, m);
// What does this print?
printf("k = %d, m = %d\n", k, m);
return 0;
}

111
ocw/1/c-primer/verifier.py Normal file
View file

@ -0,0 +1,111 @@
#!/usr/bin/python
import subprocess, os, sys, re
def exitWithError(error):
print error
sys.exit(1)
def runAndReadOutput(args):
if args is str:
args = [args]
try:
return subprocess.check_output(args)
except subprocess.CalledProcessError as e:
exitWithError("ERROR: runtime error with %s" % str(args))
def run(path): runAndReadOutput(path)
def runAndCheckSizes():
output = runAndReadOutput("./sizes")
expected_output_format = "size of %s : %d bytes"
lines = set([x.replace(" ", "") for x in output.strip().lower().split('\n')])
types = [
( "int", 4 ),
( "short", 2 ),
( "long", 8 ),
( "char", 1 ),
( "float", 4 ),
( "double", 8 ),
( "unsigned int", 4 ),
( "long long", 8 ),
( "uint8_t", 1 ),
( "uint16_t", 2 ),
( "uint32_t", 4 ),
( "uint64_t", 8 ),
( "uint_fast8_t", 1 ),
( "uint_fast16_t", 8 ),
( "uintmax_t", 8 ),
( "intmax_t", 8 ),
( "__int128", 16 ),
( "uint32_t", 4 ),
( "uint64_t", 8 ),
( "student", 8 ),
( "x", 20),
( "int*", 8 ),
( "short*", 8 ),
( "long*", 8 ),
( "char*", 8 ),
( "float*", 8 ),
( "double*", 8 ),
( "unsigned int*", 8 ),
( "long long*", 8 ),
( "uint8_t*", 8 ),
( "uint16_t*", 8 ),
( "uint32_t*", 8 ),
( "uint64_t*", 8 ),
( "uint_fast8_t*", 8 ),
( "uint_fast16_t*", 8 ),
( "uintmax_t*", 8 ),
( "intmax_t*", 8 ),
( "__int128*", 8 ),
( "uint32_t*", 8 ),
( "uint64_t*", 8 ),
( "student*", 8 ),
( "&x", 8)
]
for typ in types:
print (expected_output_format % typ)
if (expected_output_format % typ).replace(" ", "") not in lines:
exitWithError("ERROR: couldn't find type %s (or it has the incorrect value) in sizes output" % typ[0])
def runAndCheckSwap():
expected_output = "k = 2, m = 1\n"
output = runAndReadOutput("./swap")
if output != expected_output:
exitWithError('ERROR: actual output: "%s", expected "%s"' % (output, expected_output))
def build(make_arg, filename):
print "\nRunning make %s ... " % make_arg
run(["make", filename])
print "Ok!"
print "\nChecking that %s was built ... " % filename
if not os.path.isfile(filename):
exitWithError("ERROR: %s binary missing, did you rename it?" % filename)
print "Ok!"
print "Running verifying script ... "
print "\nChecking that the Makefile exists ... "
if not os.path.isfile('Makefile'):
exitWithError('ERROR: Makefile does not exist.')
print "Good!"
build("sizes", "sizes")
print "Checking output of sizes ... "
runAndCheckSizes()
print "Ok!"
build("pointer", "pointer")
run("./pointer") # Run pointer as a sanity check, but there's no output to check
build("swap", "swap")
print "Checking output of swap ... "
runAndCheckSwap()
print "Ok!"
print "LGTM"

View file

@ -0,0 +1,105 @@
# Copyright (c) 2012 MIT License by 6.172 Staff
# List all of your source files here (but not your headers), separated by
# spaces. You'll have to add to this list every time you create a new
# source file.
SRC := testbed.c matrix_multiply.c
# Set the name of your binary. Change it if you like.
PRODUCT := matrix_multiply
################################################################################
# These configuration options change how your code (listed above) is compiled
# every time you type "make". You may have to change these values to complete
# some assignments; you should also feel free to experiment with them.
################################################################################
# This option sets which compiler your code will be compiled with. Likely
# choices are icc, icpc, gcc, g++, clang
CC := clang
# These flags will be applied to your code any time it is built.
CFLAGS := -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O3
# These flags are applied only if you build your code with "make DEBUG=1". -g
# generates debugging symbols, -DDEBUG defines the preprocessor symbol "DEBUG"
# (so that you can use "#ifdef DEBUG" in your code), and -O0 disables compiler
# optimizations, so that the binary generated more directly corresponds to your
# source code.
CFLAGS_DEBUG := -g -DDEBUG -O0
# In the release version, we ask for many optimizations; -O3 sets the
# optimization level to three. -DNDEBUG defines the NDEBUG macro,
# which disables assertion checks.
CFLAGS_RELEASE := -O1 -DNDEBUG
# These flags are used to invoke Clang's address sanitizer.
CFLAGS_ASAN := -O1 -g -fsanitize=address
# These flags are applied when linking object files together into your binary.
# If you need to link against libraries, add the appropriate flags here. By
# default, your code is linked against the "rt" library with the flag -lrt;
# this library is used by the timing code in the testbed.
LDFLAGS := -lrt -flto -fuse-ld=gold
################################################################################
# You probably won't need to change anything below this line, but if you're
# curious about how makefiles work, or if you'd like to customize the behavior
# of your makefile, go ahead and take a peek.
################################################################################
# You shouldn't need to touch this. This keeps track of whether you are
# building in a release or debug configuration, and sets CFLAGS appropriately.
# (This mechanism is based on one from the original materials for 6.197 by
# Ceryen Tan and Marek Olszewski.)
OLDMODE=$(shell cat .buildmode 2> /dev/null)
ifeq ($(DEBUG),1)
CFLAGS := $(CFLAGS_DEBUG) $(CFLAGS)
ifneq ($(OLDMODE),debug)
$(shell echo debug > .buildmode)
endif
else ifeq ($(ASAN),1)
CFLAGS := $(CFLAGS_ASAN) $(CFLAGS)
LDFLAGS := $(LDFLAGS) -fsanitize=address
ifneq ($(OLDMODE),asan)
$(shell echo asan > .buildmode)
endif
else
CFLAGS := $(CFLAGS_RELEASE) $(CFLAGS)
ifneq ($(OLDMODE),nodebug)
$(shell echo nodebug > .buildmode)
endif
endif
# When you invoke make without an argument, make behaves as though you had
# typed "make all", and builds whatever you have listed here. (It knows to
# pick "make all" because "all" is the first rule listed.)
all: $(PRODUCT)
# This special "target" will remove the binary and all intermediate files.
clean::
rm -f $(OBJ) $(PRODUCT) .buildmode \
$(addsuffix .gcda, $(basename $(SRC))) \
$(addsuffix .gcno, $(basename $(SRC))) \
$(addsuffix .gcov, $(SRC) fasttime.h)
# This rule generates a list of object names. Each of your source files (but
# not your header files) produces a single object file when it's compiled. In
# a later step, all of those object files are linked together to produce the
# binary that you run.
OBJ = $(addsuffix .o, $(basename $(SRC)))
# These rules tell make how to automatically generate rules that build the
# appropriate object-file from each of the source files listed in SRC (above).
%.o : %.c .buildmode
$(CC) $(CFLAGS) -c $< -o $@
%.o : %.cc .buildmode
$(CC) $(CFLAGS) -c $< -o $@
%.o : %.cpp .buildmode
$(CC) $(CFLAGS) -c $< -o $@
# This rule tells make that it can produce your binary by linking together all
# of the object files produced from your source files and any necessary
# libraries.
$(PRODUCT): $(OBJ) .buildmode
$(CC) -o $@ $(OBJ) $(LDFLAGS)

View file

@ -0,0 +1,95 @@
/**
* Copyright (c) 2014 MIT License by 6.172 Staff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
**/
#ifndef INCLUDED_FASTTIME_DOT_H
#define INCLUDED_FASTTIME_DOT_H
#include <assert.h>
#ifdef __MACH__
#include <mach/mach_time.h> // mach_absolute_time
typedef uint64_t fasttime_t;
// Return the current time.
static inline fasttime_t gettime(void) {
return mach_absolute_time();
}
// Return the time different between the start and the end, as a float
// in units of seconds. This function does not need to be fast.
// Implementation notes: See
// https://developer.apple.com/library/mac/qa/qa1398/_index.html
static inline double tdiff(fasttime_t start, fasttime_t end) {
static mach_timebase_info_data_t timebase;
int r = mach_timebase_info(&timebase);
assert(r == 0);
fasttime_t elapsed = end-start;
double ns = (double)elapsed * timebase.numer / timebase.denom;
return ns*1e-9;
}
static inline unsigned int random_seed_from_clock(void) {
fasttime_t now = gettime();
return (now & 0xFFFFFFFF) + (now>>32);
}
#else // LINUX
// We need _POSIX_C_SOURCE to pick up 'struct timespec' and clock_gettime.
// #define _POSIX_C_SOURCE 200809L
#include <time.h>
typedef struct timespec fasttime_t;
// Return the current time.
static inline fasttime_t gettime(void) {
struct timespec s;
#ifdef NDEBUG
clock_gettime(CLOCK_MONOTONIC, &s);
#else
int r = clock_gettime(CLOCK_MONOTONIC, &s);
assert(r == 0);
#endif
return s;
}
// Return the time different between the start and the end, as a float
// in units of seconds. This function does not need to be fast.
static inline double tdiff(fasttime_t start, fasttime_t end) {
return end.tv_sec - start.tv_sec + 1e-9*(end.tv_nsec - start.tv_nsec);
}
static inline unsigned int random_seed_from_clock(void) {
fasttime_t now = gettime();
return now.tv_sec + now.tv_nsec;
}
// Poison these symbols to help find portability problems.
int clock_gettime(clockid_t, struct timespec *) __attribute__((deprecated));
time_t time(time_t *) __attribute__((deprecated));
#endif // LINUX
#endif // INCLUDED_FASTTIME_DOT_H

View file

@ -0,0 +1,96 @@
/**
* Copyright (c) 2012 MIT License by 6.172 Staff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
**/
#include "./matrix_multiply.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <math.h>
#include <string.h>
// #include "./tbassert.h"
// Allocates a row-by-cols matrix and returns it
matrix* make_matrix(int rows, int cols) {
matrix* new_matrix = malloc(sizeof(matrix));
// Set the number of rows and columns
new_matrix->rows = rows;
new_matrix->cols = cols;
// Allocate a buffer big enough to hold the matrix.
new_matrix->values = (int**)malloc(sizeof(int*) * rows);
for (int i = 0; i < rows; i++) {
new_matrix->values[i] = (int*)malloc(sizeof(int) * cols);
}
return new_matrix;
}
// Frees an allocated matrix
void free_matrix(matrix* m) {
for (int i = 0; i < m->rows; i++) {
free(m->values[i]);
}
free(m->values);
free(m);
}
// Print matrix
void print_matrix(const matrix* m) {
printf("------------\n");
for (int i = 0; i < m->rows; i++) {
for (int j = 0; j < m->cols; j++) {
printf(" %3d ", m->values[i][j]);
}
printf("\n");
}
printf("------------\n");
}
// Multiply matrix A*B, store result in C.
int matrix_multiply_run(const matrix* A, const matrix* B, matrix* C) {
/*
tbassert(A->cols == B->rows,
"A->cols = %d, B->rows = %d\n", A->cols, B->rows);
tbassert(A->rows == C->rows,
"A->rows = %d, C->rows = %d\n", A->rows, C->rows);
tbassert(B->cols == C->cols,
"B->cols = %d, C->cols = %d\n", B->cols, C->cols);
*/
for (int i = 0; i < A->rows; i++) {
for (int j = 0; j < B->cols; j++) {
for (int k = 0; k < A->cols; k++) {
C->values[i][j] += A->values[i][k] * B->values[k][j];
}
}
}
return 0;
}

View file

@ -0,0 +1,58 @@
/**
* Copyright (c) 2012 MIT License by 6.172 Staff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
**/
/**
* Matrix Multiply
*
*
* Declarations here are your API specification -- we expect that your
* code defines and correctly implements these functions and does not modify
* the way the reference implementation uses variables mentioned here,
* so that we may call them from testbed.c and any other testing software
* that we write!
*
* Deviating from this API may cause your program to fail all of our tests.
**/
#ifndef MATRIX_MULTIPLY_H_INCLUDED
#define MATRIX_MULTIPLY_H_INCLUDED
typedef struct {
int rows;
int cols;
int** values;
} matrix;
// Multiply matrix A*B, store result in C.
int matrix_multiply_run(const matrix* A, const matrix* B, matrix* C);
// Allocates a row-by-cols matrix and returns it
matrix* make_matrix(int rows, int cols);
// Frees an allocated matrix
void free_matrix(matrix* m);
// Print matrix
void print_matrix(const matrix* m);
#endif // MATRIX_MULTIPLY_H_INCLUDED

View file

@ -0,0 +1,73 @@
/**
* Copyright (c) 2014 MIT License by Tao B. Schardl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
**/
#ifndef _TBASSERT_H_
#define _TBASSERT_H_ 1
#ifndef NDEBUG
/**************************************************************************
* Library of debugging macros.
*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
// Print a message to STREAM when DEBUG = 1. This macro takes the
// same arguments as FPRINTF().
#define DEBUG_FPRINTF(STREAM, ...) \
do { \
fprintf(STREAM, "%s:%d (%s) ", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
fprintf(STREAM, __VA_ARGS__); \
} while (0)
// Print a message to STDERR when DEBUG = 1. This macro takes the
// same arguments as PRINTF().
#define DEBUG_EPRINTF(...) DEBUG_FPRINTF(stderr, __VA_ARGS__);
// If PREDICATE is true, do nothing. Otherwise, print an error with
// the specified message to STDERR. This macro only operates when
// DEBUG = 1. This macro takes a PREDICATE to evaluate followed by
// the standard arguments to PRINTF().
#define DEBUG_ASSERT(PREDICATE, ...) \
do { \
if (!(PREDICATE)) { \
fprintf(stderr, "%s:%d (%s) Assertion " #PREDICATE " failed: ", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} \
} while (0)
#define tbassert DEBUG_ASSERT
#else
#define DEBUG_PRINTF(...) // Nothing.
#define DEBUG_EPRINTF(...) // Nothing.
#define DEBUG_ASSERT(...) // Nothing.
#define tbassert(...) // Nothing.
#endif
#endif // _TBASSERT_H_

View file

@ -0,0 +1,154 @@
/**
* Copyright (c) 2012 MIT License by 6.172 Staff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
**/
/**
* testbed.c:
*
* This file runs your code, timing its execution and printing out the result.
**/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "./fasttime.h"
#include "./matrix_multiply.h"
int main(int argc, char** argv) {
int optchar = 0;
int show_usec = 0;
int should_print = 0;
int use_zero_matrix = 0;
// Always use the same seed, so that our tests are repeatable.
unsigned int randomSeed = 1;
matrix* A;
matrix* B;
matrix* C;
const int kMatrixSize = 4;
// Parse command line arguments
while ((optchar = getopt(argc, argv, "upz")) != -1) {
switch (optchar) {
case 'u':
show_usec = 1;
break;
case 'p':
should_print = 1;
break;
case 'z':
use_zero_matrix = 1;
break;
default:
printf("Ignoring unrecognized option: %c\n", optchar);
continue;
}
}
// This is a trick to make the memory bug leads to a wrong output.
int size = sizeof(int) * 4;
int* temp[20];
for (int i = 0; i < 20; i++) {
temp[i] = (int*)malloc(size);
memset(temp[i], 1, size);
}
int total = 0;
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 4; j++) {
total += temp[i][j];
}
}
if (!total) printf("Trick to stop mallocs from being optimized out.");
for (int i = 0; i < 20; i++) {
free(temp[i]);
}
fprintf(stderr, "Setup\n");
A = make_matrix(kMatrixSize, kMatrixSize+1);
B = make_matrix(kMatrixSize, kMatrixSize);
C = make_matrix(kMatrixSize, kMatrixSize);
if (use_zero_matrix) {
for (int i = 0; i < A->rows; i++) {
for (int j = 0; j < A->cols; j++) {
A->values[i][j] = 0;
}
}
for (int i = 0; i < B->rows; i++) {
for (int j = 0; j < B->cols; j++) {
B->values[i][j] = 0;
}
}
} else {
for (int i = 0; i < A->rows; i++) {
for (int j = 0; j < A->cols; j++) {
A->values[i][j] = rand_r(&randomSeed) % 10;
}
}
for (int i = 0; i < B->rows; i++) {
for (int j = 0; j < B->cols; j++) {
B->values[i][j] = rand_r(&randomSeed) % 10;
}
}
}
if (should_print) {
printf("Matrix A: \n");
print_matrix(A);
printf("Matrix B: \n");
print_matrix(B);
}
fprintf(stderr, "Running matrix_multiply_run()...\n");
fasttime_t time1 = gettime();
matrix_multiply_run(A, B, C);
fasttime_t time2 = gettime();
if (should_print) {
printf("---- RESULTS ----\n");
printf("Result: \n");
print_matrix(C);
printf("---- END RESULTS ----\n");
}
if (show_usec) {
double elapsed = tdiff(time1, time2);
printf("Elapsed execution time: %f usec\n",
elapsed * (1000.0 * 1000.0));
} else {
double elapsed = tdiff(time1, time2);
printf("Elapsed execution time: %f sec\n", elapsed);
}
return 0;
}

52
ocw/1/sizes.s Normal file
View file

@ -0,0 +1,52 @@
.file "sizes.c"
.text
.globl subprocedure
.type subprocedure, @function
subprocedure:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movl -20(%rbp), %edx
movl -24(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size subprocedure, .-subprocedure
.globl main
.type main, @function
main:
.LFB7:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, -8(%rbp)
movl $5, -4(%rbp)
movl -4(%rbp), %edx
movl -8(%rbp), %eax
movl %edx, %esi
movl %eax, %edi
call subprocedure
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE7:
.size main, .-main
.ident "GCC: (GNU) 15.1.1 20250425"
.section .note.GNU-stack,"",@progbits

BIN
ocw/bit-hacks/a.out Executable file

Binary file not shown.

2
ocw/bit-hacks/a.py Normal file
View file

@ -0,0 +1,2 @@
class S:
def __init__(self)

View file

@ -0,0 +1,2 @@
-O2
-masm=intel

12
ocw/bit-hacks/hacks.cc Normal file
View file

@ -0,0 +1,12 @@
#include <iostream>
int main() {
int x = 123;
int y = 123123;
std::cout << x;
std::swap(x, y);
std::cout << y;
return 0;
}

BIN
ocw/bit-hacks/structop Executable file

Binary file not shown.

15
ocw/bit-hacks/structop.cc Normal file
View file

@ -0,0 +1,15 @@
#include <cstddef>
#include <iostream>
struct S {
char b;
int i;
};
int main() {
S s;
std::cout << offsetof(S, i) << '\n';
return 0;
}

BIN
ocw/profiling/a.out Executable file

Binary file not shown.

File diff suppressed because it is too large Load diff

89225
ocw/profiling/demangled.s Normal file

File diff suppressed because it is too large Load diff

39
ocw/profiling/notes.md Normal file
View file

@ -0,0 +1,39 @@
# profiling
## intro
### instrumentation: overall timing (usual idea)
- while timing a clock with `time_the_clock.cc`, i erroneously initialized a
`chrono::microseconds` default. this can be seen in the STL source: the default constructor
initializes the `Rep` (repeated value, the unit for the duration) by
default. A `microsecond` is a long here - this became garbage.
- NOTE: timing the clock (with 0 optimization) took ~0ns and is not of significance for my profiling. I concluded this by compiling with `-O0` and de-mangling with c++filt we can see this is the case: we can see this is the case and nothing is being optimized out:
```asm
.L585:
call std::chrono::_V2::system_clock::now()@PLT
movq %rax, -64(%rbp)
call std::chrono::_V2::system_clock::now()@PLT
```
However, I acknowledge that this code is not run one-for-one. I don't have the
knowledge to assess caching done by the actual CPU itself, or even other side
effects like inlining.
So far, though, one lesson of profiling is:
> Only profile the code *actually* being profiled
### statistical profiling
- more accurate by *experimental* virtue - probabilistic look
- imagine the execution of the program as a "strip" of time
- system-specific, but so was before
- statistical: stats
- program simulation: ll
## exercise 1
- use cachegrind/valgrind/asan on cf problem
- apply bentley's rules to some code
- begin developing a strategy for how to profile things

26698
ocw/profiling/output.svg Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
ocw/profiling/perf-tester Executable file

Binary file not shown.

View file

@ -0,0 +1,19 @@
#include <iostream>
void complex_method() {
int i = 0x12323333- 1230*123213;
long x = -23;
std::cout << "x: " << x << '\n';
while (--i) {
x ^= (x - 1);
for (int j = 0; j < 50; ++j) {
x = x * x * x;
}
}
}
int main() {
complex_method();
return 0;
}

BIN
ocw/profiling/perf.data Normal file

Binary file not shown.

BIN
ocw/profiling/perf.data.old Normal file

Binary file not shown.

114179
ocw/profiling/perf.script Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
#include <chrono>
#include <iostream>
#include <print>
using namespace std;
constexpr static size_t TRIALS = 100000;
int main() {
chrono::microseconds diffs_ms{0};
for (size_t loop_var = 1; loop_var <= TRIALS; ++loop_var) {
auto t1 = chrono::high_resolution_clock::now();
auto t2 = chrono::high_resolution_clock::now();
diffs_ms += chrono::duration_cast<chrono::microseconds>(t2 - t1);
}
print("measuring the clock in c++ 23 {} trials had an average time duration "
"of: {} microseconds, or {} milliseconds",
TRIALS, diffs_ms / TRIALS,
chrono::duration_cast<chrono::milliseconds>(diffs_ms / TRIALS));
return 0;
}

89225
ocw/profiling/time_the_clock.s Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
# performance
## [profiling - algorithmica](https://en.algorithmica.org/hpc/profiling/)
## [performance analysis and tuning](https://en.algorithmica.org/hpc/profiling/)

816
perf-cpp/cpp.md Normal file
View file

@ -0,0 +1,816 @@
# CPP
## [learncpp](https://www.learncpp.com/)
- compilation process: preprocess -> compilation -> assembly -> linking
- lexing for grammar validity -> ast type checking
- files are compiled top to bottom, & individually (must include libraries
multiple times)
- e.g. below, type checker evaluates, sees f returns `void` -> pairs with
`std::cout` operator `<<` -> this is invalid -> *compile-time* caught
```cpp
#include <iostream>
void printA()
{
std::cout << "A\n";
}
int main()
{
std::cout << printA() << '\n';
return 0;
}
```
- initialization
- why list initialization -> narrowing conversions disallowed
- [operator precendece](https://en.cppreference.com/w/cpp/language/operator_precedence.html)
- nested functions disallowed
- many features of cpp don't nec. have rhyme or reason; it is a language
[with history](https://www.reddit.com/r/cpp/comments/199ho2b/why_doesnt_standard_c_support_nested_functions/) for good or bad
- cpp compiles sequentially (i.e. top to bottom)
- <u>One Definition Rule</u>: per file, per scope, one definition only; per
program too; types/templates/inline functions can have other definitions
- ? why are header files usually omitted in c++ compilation processes?
- ? why does the cpp - include header structure in projects work, espec. wrt
ODR?
- NOTE: *compiling* does not need impls (just needs ) -> *linking* does
- NOTE: research about linking later, but just know linking has a symbol
table to map symbols to literaly code locations
### namespaces
- *simple* -> wrap simple name
- "name mangling" includes the namespace prefix in compilation -> easy to
identify
## preprocessing
- when is it done?
- for each cpp file, copy-paste in the includes & compile into translation
units separately
- what's the output of pre-processsed files called?
- Lesson: use macros sparingly besides eliminating code compilation (i.e. in
libraries) and compilation-specific processes
- `""` vs. `<>` in includes: look locally relative to the path, then
system/*only* look in the system
- Why not use relative includes (~~configure the compile-time include path instead~~)
- Why even use header guards? What's the common pattern that necessitates them?
- 1 file including 2 files that each include another file -> duplicate
definition
- ? why do header guards resolve this problem? ~~because each translation unit
is treated separately by the pre-processor. files are compiled separately but
a file compiling joint ones doesn't duplicate includes via the guard.~~
- long story short, every file must have one of all each included file ->
prevent ODR violations
- ? why don't define methods in header files? ~~multiple cpp can include
headers, leading to ODR violations~~
- only have ONE function implementation in source files -> compilation
resolves with declarations & implementations linked easily
## type conversion
- <u>implicit conversions</u> convert types when acceptable
- pre-defined set of compiler rules
- why is using const in value parameters useless?
## optimization
- what's the official rule for how c++ compilres can change code? ~~when the
"observable behavior" is identical - i.e. cahnge anything if output is the
same~~
- methods:
1. constant folding
2. dead code elimination
## constants
- "by default, expressions are evaluated at \_"?
- it's up to the *compiler* as to whether *anything* is evaluated at compile
time
- <u>constexpr</u>: declares value as a compile-time available constant - all args *must* be
evaluatable at compile time (i.e. be constant expressoions) - BUT... this is optional!
- values must be KNOWN -> not nec. imply compilation
- "constexprness" implies constness
- `std::string_view` is a fragile container
## [order of operations](https://en.cppreference.com/w/cpp/language/operator_precedence.html)
- why is this bad? ~~according to c++ spec, order of function evaluation is not
specified - generally speaking, args should not have side effects~~
```cpp
auto x = 5;
f(x++, ++x);
```
- what does this return, and why? what does it teach us abou tthe ternary
operations?
- ~~due to operator precedence, 0 is first printed; then the returned
std::cout& is implicitly cast to a boolean and the result of the terary is
discarded~~
```cpp
#include <iostream>
int main() {
int x { 2 };
std::cout << (x < 0) ? "negative" : "non-negative";
return 0;
}
```
- NOTE: `<=>`, bitwise operators, and more have lower priority than `<<`
- I allocate N bits into a `std::bitset`. How many bits of memory are allocated
and why?
~~ceil(N / bits per machine word) * number bits per word (rounded up) -
bitsets are fixed size, contiguous arrays of machine words for convenient
accessing~~
## scopes
- explain lifetime management in c++
- an identifier can have multiple scopes - T/F
- how does the compiler search for scope resolution?
||it works from the inside out resolving symbols||
- how can i refer to x in the outer example? ||use the scope resolution
operator: `f::x`||
```cpp
void f() {
int x;
{
int x;
}
}
```
## linkage
- what is linkage? ||linkage determines visibility & to the linker||
- can the linker see variables with internal linkage? ||intuitively no - they'll
never need to be linked because they are not accessible from other translation
units||
- functions default to {external, internal} linkage ||external||
- non-constant global variables? ||external||
- how to declare constant global to have external linkage? ||add the [storage class specifier](https://en.cppreference.com/w/cpp/language/storage_duration.html) `extern`||
- why can `extern` variables not be `constexpr`? ||value must be evaluatable at
compile-time - if another file sets the value, the compiler isn't
sophisticated to know (it compiles files in isolation)||
- Whats the difference between a variables scope, duration, and linkage? What kind of scope, duration, and linkage do global variables have?
- ||scope -> where defined/accessible in the code; duration ->
creation/destruction bounds (can be different in more complex areas? give an
example), linkage -> visibility beyond translation unit||
## [inlining](https://en.cppreference.com/w/cpp/language/inline.html)
- centrally concerned with *linkage*
- external linkage can cause ODR violations -> resolve with `inline`
- when to not inline? ||size of the inlined function outweighs the overhead of
inlining itself||
- why can you not force the compiler to inline?
- why is `inline` not to be used for inlining?
- ||inlining is a per-function call concept, but the keyword makes it apply to
all scenarios||
- `inline` is about removing ODR violations across *multiple* different files.
- how does this vary from header guards?
- when should you use inline?
- `inline` really means ||multiple definitions are permitted|| instead of inline the call
- NOTE: this still honestly doesn't make much sense to me
- Review linkage, compilation process, ODR, and inlining
- We usually just want ONE definition - so we keep implementations in ||source||
files so that on compilation the ||linker|| can easily find the function
definition (which it can do because it has ||external|| linkage by default)
- When defining something like a function ||implementation|| in a ||header||
file, this pattern is broken. why? ||multiple function impls with external
linkage will exist||
- inline then allows separate ||translation units||, indeed compiled separately, to resolve the symbol fine
- marking something as `inline` does/does not ||does not|| change the storage class specifier. the linker ||merges|| multiple definitions of variables marked inline
- `inline` variables have ||external|| linkage by default - why? ||duh - so
linker can resolve between TUs||
## static
- has so many different meaning
- What does `static` refer to inside/outside a function? ||static *storage
duration*/*internal linkage*||
variable to start/end at the time of the program
- how do I give a function internal linkage? ||mark as `static`||
## scoping and brackets
- which does the else bind to? ||closest/nearest unmatched if -> the if (y)
block||
- explain loops without brackets in terms of grammar
- ||basically, grammatically an if/for/etc. cover ones statement. an enclosing body with brackets is a <u>compound statement</u>. no
brackets -> the first statement in the tree is grabbed||
- why does this then work with chained elses and else ifs? note that else ifs are
parsed as ifs inside of else blocks
```cpp
if (x)
if (y)
a();
else
b();
```
## switch statements
- compilers are smart, and may do the following for switch statements:
1. direct access jump tables
2. binary search when too big
3. re-indexing (i.e. values start at large n)
## loops
- mostly get compiled to the same thing
## function overloading implicit type conversion
- why is it needed? ||internal representation of different types differs||
- `using` keyword does a variety of things
- what happens when multiple function candidates are available?
- overload resolution -> choose ONE best candidate (if multiple, error)
- What's the output (and why?)
- ||double because there's a promotion to float||
```cpp
#include <iostream>
void f(int) { std::cout << "f(int)\n"; }
void f(double) { std::cout << "f(double)\n"; }
int main() {
f(3.14f);
int x = 3.14f; // also conversion
}
```
- in <u>function overloading</u>, acc. to C++ spec resolve function choices:
1. exact match
2. promote *arguments*
3. user defined conversions
4. ellipses
5. give up
- ? what's the difference between compiler vs. linker resolving functions?
- ~~compiler resolves function calls via OVERLOADING - indeed, the compiler
must know all function signatures. subsequently, each
function is then mapped to in the linker phase.~~
- What's the output (and why?)
- ||compilation error -> CONVERSION of the same rank||
```cpp
void f(long) { std::cout << "f(long)\n"; }
void f(unsigned long) { std::cout << "f(unsigned long)\n"; }
int main() {
f(3.14f);
return 0;
```
- NOTE: conversion is complex
- promotion -> special, correct promotion -> prioritized (prioritized first)
- only includes small types, not like `long`
- conversion -> otherwise
- compilers do the five following conversions, and in which order?
||
1. exact (including qualifiers such as cv, array-to-pointer, etc.)
2. promotion
3. conversion (and any path, promotion + conversion, etc)
4. user-defined
5. variadic (i.e. smash into an ellipses)
||
- valid or not, and why?
- ||invalid - return types not used in function overloading for a)
compatibility reasons with C and b) trouble distinguishing between desired
return type (how can you indicate which function you want when there isn't
always a straightforward way to do such?). e.g. `auto X = x(); f(());`,
etc. Generally, it's convenient to just look at call context & know return
value after deducing the right function call.||
- || in other words, a function's type signature is everything but the
return type.||
```cpp
int x();
double x();
```
- exactly what does this do?
- || *halt* compilation if the function is called. code is still compiled,
but `delete` forbids the call||
```cpp
template <typename T>
void printInt(T x) = delete;
```
### default arguments
- are default args part of function signature ||no||
- how are default args instantiated
- what's the output of the following code, and why?
- ||behaves as expected. compile substitutes in the default args at the call
site, so the calls become `g(int x=foo())`||.
```cpp
int foo() {
static int s = 0;
return ++s;
}
void g(int x = foo()) {
// ...
}
int main() {
g();
g();
}
```
- does this compile? y or no? ||no - default args not considered in function
signature in overload resolution process - call is ambiguous||
```cpp
void print()
{
std::cout << "void\n";
}
void print(int x=0)
{
std::cout << "int " << x << '\n';
}
int main() { print(); }
```
### templates
- how do templates work in the compiler?
- ||an internal symbol table - one template blueprint itself does not generate
machine code (instantiations do)||
- say i have two functions - one regular, one templated. how can i prefer the
templated function? do i even need to?
- ||if you want to target the templated function, which is more generic and
thus not prioritized by the compiler, wrap it in `<>`||
```cpp
template<typename T>
void print();
void f(bool);
// ??
f(true);
f<(bool)>(); // NOTE: bool is optional
```
- what's the output? || 1) 2) 1) - consider the instantiated code per the
compiler - one static local variable per template specialization ||
- what about here? ||second function called. template can create an exact match
which is preferred over promotion||.
```cpp
void f(int x) { ... }
void f(auto x) { ... }
// ??
f(short{3});
```
```cpp
#include <iostream>
template <typename T>
void printIDAndValue(T value)
{
static int id{ 0 };
std::cout << ++id << ") " << value << '\n';
}
int main() {
printIDAndValue(12);
printIDAndValue(13);
printIDAndValue(14.5);
return 0;
}
```
- ? concepts and generics, best ways to link together?
- what's partial ordering of templates?
- ? what's the *entire* way compilers resolve function calls?
```cpp
template <typename T>
auto add(T x, T y) {
return x + y;
}
template <typename T, typename U>
auto add(T x, U y) {
return x + y;
}
```
- what's wrong with this? how do i fix it?
- ||add specializations or an else clause with `constexpr`. picture the compiler - it needs to
instantiate all proper templates on compilation. in some sense, the
compiler is literally executing the code.
```cpp
template <int N>
constexpr long long fibonacci() {
static_assert(N >= 0);
if (N <= 1) { return N; }
return fibonacci<N - 1>() + fibonacci<N - 2>();
}
```
- NOTE: this is a sharp edge. skip it, honestly
- functions instantiated from templates are implicitly ||`inline`||. Why? ||must
be so that different, identical specializations in files do not violate the
ODR.||
- the odr is a compile and/xor link time concept ||and||
## pointers and references
- how do references work under the hood?
- alias to variable only known to compiler - implicitly dereffed
- NEVER reassignable
- output?
```cpp
int x = 5;
int y = 4;
int& z = x;
z = y; // x holds value of 4 -> can never reassign alias
(*x) = y;
```
- what's the output?
- ||A 5 A; reference calls always implicitly resolve to (\*ref) by the compiler - "syntactic sugar". In other words, it's impossible to actually inspect the reference pointer itself.||
```cpp
#include <iostream>
void printAddresses(int val, int& ref)
{
std::cout << val << '\n';
std::cout << &ref << '\n';
}
int main() {
int x { 5 };
std::cout << "The address of x is: " << &x << '\n';
printAddresses(x, x);
}
```
- will this compile? ||it has a memory leak - that doesn't mean it won't compile
(it is valid c++, sigh)||
```cpp
const std::string& getProgramName() {
const std::string programName { "Calculator" };
return programName;
}
// automatic storage duration of `programName` - destroyed
```
- auto and what not - name the types, assuming `getRef()` returns `T`:
- `auto x = getRef()` -> ||T (reference discarded)||
- `auto& x = getRef()` -> ||T&. This is known as "reapplying the reference and
can also be done with `const`"||
- `auto x = getConstRef()` -> ||T (const discarded)||
- `auto x = getPointer()` -> ||T\* (pointer kept - notion of
converting/dropping is incorrect, its sort of its own type)||
- `auto* x = getPointer()` -> ||T\* (pointer kept)||
- low-level vs. top level const?
- ||A top-level const applies to the object itself (e.g. const int x or int* const ptr)||
- ||A low-level const applies to the object accessed through a reference or pointer (e.g. const int& ref, const int* ptr).||
## enums
- by default, `enum`s are ||unscoped|| which means they ||leak into the
scope they're defined in||. For this reason default
to `enum`s keyed with the word ||`class`||, or "||scoped||" enums. We just
need to access them with the ||scope resolution|| operator.
not leak.
- ||bad, good - unscoped do not implicitly convert||
```cpp
enum class X { A };
enum Y { A };
X::A == 0;
Y::A == 0;
```
- ||NO but yes if unscoped, NEVER||
```cpp
void f() {
// NOTE: even enum does not work here (both scoped inside)
enum class A { B };
// does this compile?
A::B;
}
// this?
A::B;
```
## structs/classes
- `static` in structs means one variable for the lifetime
- where do static class/struct vars live in memory? ||not in struct, prob in
the data segment||
- any function implementation in a `struct` is implicitly marked ||`inline`|| - why?
- why declare a static struct variable `inline`? ||so you can declare it once inside the struct (C++17+)||
- NOTE: only ever makes sense to declare variables as `inline` when done
static inside a class - shared, program-living variables. i.e. marking
object-local variable as `inline` is nonsensical - it's "already `inline`"
- static-static interaction only
- no `this` pointer -> must access via `ClassName::{}`
- structs are like/not like member functions in the sense that they can/cannot
be declared in any order
- specification default vs. class
- valid? & why? ||yes, const is part of signature. useful for things like
operator overload, const & non-const versions||
- what is `const` mem func -> ||cannot modift class internals||
- When can you not call non-`const` member functions? ||from const objects ->
may mutate state||
- pretty straightforward, which is why you can/cannot call non-const MF from
non-const objects (||can||)
```cpp
// ??
class A{
void f() const;
void f();
}
```
### access specification
- private/public/protected
- given your definitions, why is the code below valid or invalid? ||valid -
`private` -> *any* object & friend of class (inheritor or not) can touch its members||
```cpp
class A{
int x;
void f(A a) {
// ??
a.x;
}
}
```
- structs/class differ in that struct/class AS is ||public/private||
- access specification is a ||compile||-time construct and occurs before/after
(||after||) method resolution in the compilation process
- good or bad (||bad - best match, then resolve specification||)
```cpp
struct Gate {
private:
void calibrate(int);
public:
void calibrate(double);
};
void run(Gate& g) {
// ??
g.calibrate(7);
}
```
### struct/class memory management
- struct members can/cannot be reordered and can/cannot have padding inserted
- in terms of the following memory model:
- <u>code</u>: code itself
- <u>data</u>: globals, statics, string literals
- <u>stack</u>: stack frames, local vars, etc
- <u>heap</u>: heap-allocated things
```cpp
struct Widget {
int id; // per-object data
std::string name; // per-object data
static int total_count; // one global variable
static constexpr double pi = 3.14159; // goes in rodata
void ping(); // function
virtual void vfunc(); // function pointer in vtable
};
```
- ... member functions are in (||code, so you don't have multiple
per-instantiation||), regular variables in ||stack||, static in ||data||,
virtual stuff ||also somewhere in code - like having one virtual pointer||
- WHY does this memory management make sense?
### construction
- do constructors create objects || no they initialize ||
- why not `const`?
- follow normal conversion rules
- ouptput: ||member initializer list always takes precedence||
- NOTE: member IL != IL
```cpp
class A {
public:
A(int x) : x(x) {}
int x{2};
};
// ??
A{}.x;
```
- members are initialized in order of declaration in initialize list (why? no
idea)
```cpp
class Foo {
private:
int m_x{};
int m_y{};
public:
Foo(int x, int y)
// m_x is ALWAYS garbage
: m_y { std::max(x, y) }, m_x { m_y }
{}
};
```
- delegating and chaining constructors can be usefukl for off-loading logic
- CALLING CTORS of *other* classes and *our own* in CTORS IS PERFECTLY FINE!
- more rules:
- T/F: if I have constructors but no default, c++ creates an implicit one for
me ||F||
- T/F: if I have no default constructors, c++ makes ||T||
- Say you want to disable copying/default construction. I claim you can just
make the methods private. Does this work? ||Yes - but members of the
class/inheritors/etc. can still call it -> defeating the purpose - just use
`= delete`||
- anything wrong? ||incompete type - infinite recursion||
```cpp
class A {
A(A a) {}
};
```
- why should copy constructors not have side effects? ||if copy elision occurs,
the side effects will not. copy elision is immune to the ["as-if" rule](https://en.cppreference.com/w/cpp/language/as_if.html)||
- what is [(N)RVO](https://en.cppreference.com/w/cpp/language/copy_elision.html) and which c++ concept is behind it? ||copy elision & copy
constructors||
- does this compile? || no - only one user-defined constructor can be applied
(trying to go from `std::string` -> `std::string_view` -> `std::string`)||
- [user-defined types](https://www.learncpp.com/cpp-tutorial/introduction-to-program-defined-user-defined-types/) are also for STL
```cpp
class Employee {
private:
std::string m_name{};
public:
Employee(std::string_view name)
: m_name{ name } { }
const std::string& getName() const { return m_name; }
};
void printEmployee(Employee e) {
std::cout << e.getName();
}
int main() {
printEmployee("Joe");
return 0;
}
```
- ? know each constructor syntax - which does this call?
```cpp
Y y = Y(5); // cpp isn't stupid -> calls Y::Y(const& y), the copy constructor - not default + assigned
Y y = Y(); // default & copy, but copy elided (c++17+) -> just default
Y o;
Y y(o); // textbook copy
Y y = Y(Y()); // one defeault - BOTH elided
```
- `explicit` - only accept exact value type (no implicit conversions)
- why use `explicit` -> implicit conversions
```cpp
class A {
public:
int a;
A(int a) : a(a) {}
void meth(A a) {}
};
A a = A(true); // this is valid when A::A(int) is not explicit
a.meth(A(false)); // so i can do this too
```
- called by `static_cast` just fine, too
### this pointer
- "Every non-static member function has an implicit parameter called this."
- how does `this` and implicit `this` work?
- inserted implicitly
- what's the type of `this` in non-const/const member functions? ||
`TheClass\* const` (const pointer - you can still change underlying object)/const TheClass\* const (you cannot change underlying object, so pointer to
const)||
- NOTE: references didn't exist when c++ was made, so even tho it should be a
reference it's not
```cpp
class MethodChain {
MethodChain& mc() {
// deref -> automatically aliased in return type
return *this;
}
};
```
- ODR again - why does defining classes in headers "just work?" - because class
member functions defined ||& implemented fully in the header|| are ||implicitly marked as `inline`||
- I could just define an entire class in a header - why not? ||organization +
increased compile time -> recompile header + all deps on change, rather than
just cpp source file)
- why do class variables and other things not need to be marked `inline`
||***member functions have external linkage by default***. other stuff does
not and is a per-object local storage - is has NO linkage||
### more `static`
- static vars are/are not associated with the lifetime of a class ||are not -
start & end of program - can access w/ 0 instances||
```cpp
class A {
static x;
};
A::x; // valid
```
- say you want to shield static class vars - how? ||make private - access
specifiers trump||
- static *member functions* have/don't have a `this` pointer ||don't||
- therefore, they can/cannot call non-static functions - why? ||cannot -
non-static member functions need an implicit this object point to operate
on, and statics do not have this||
# [beginning c++ 23: beginner to pro](https://www.amazon.com/Beginning-C-23-Beginner-Pro/dp/1484293428)

3
perf-cpp/readme.md Normal file
View file

@ -0,0 +1,3 @@
# performance
c++ and performance notes and resources

View file

@ -0,0 +1,9 @@
BasedOnStyle: Google
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: false
AllowShortLoopsOnASingleLine: false

35
perf-cpp/scripts/.clangd Normal file
View file

@ -0,0 +1,35 @@
CompileFlags:
Add:
-O2
-Wall
-Wextra
-Wpedantic
-Wshadow
-Wformat=2
-Wfloat-equal
-Wlogical-op
-Wshift-overflow=2
-Wnon-virtual-dtor
-Wold-style-cast
-Wcast-qual
-Wuseless-cast
-Wno-sign-promotion
-Wcast-align
-Wunused
-Woverloaded-virtual
-Wconversion
-Wsign-conversion
-Wmisleading-indentation
-Wduplicated-cond
-Wduplicated-branches
-Wlogical-op
-Wnull-dereference
-Wformat=2
-Wformat-overflow
-Wformat-truncation
-Wdouble-promotion
-Wundef
-DLOCAL
-Wno-unknown-pragmas
-e -std=c++23
-e -std=c++23

9
perf-cpp/scripts/a.cc Normal file
View file

@ -0,0 +1,9 @@
#include <iostream>
#include "a.hh"
int main() {
std::cout << add();
return 0;
}

3
perf-cpp/scripts/a.hh Normal file
View file

@ -0,0 +1,3 @@
#pragma once
int add() {return 1;}

View file

@ -0,0 +1,29 @@
#include <iostream>
#include <bitset>
using namespace std;
#include <bitset>
#include <iostream>
std::bitset<4> rotl(std::bitset<4> bits) {
return (bits << 1) | (bits >> 3);
}
void william() {
int will;
if (69)
int will;
}
int main()
{
std::bitset<4> bits1{ 0b0001 };
std::cout << rotl(bits1) << '\n';
std::bitset<4> bits2{ 0b1001 };
std::cout << rotl(bits2) << '\n';
return 0;
}

48
perf-cpp/scripts/ch11.cc Normal file
View file

@ -0,0 +1,48 @@
/*
Write a constexpr function template with a non-type template parameter that
returns the factorial of the template argument. The following program should
fail to compile when it reaches factorial<-3>().
*/
template <int N>
constexpr long long fibonacci() {
static_assert(N >= 0);
if constexpr (N <= 1) {
return N;
} else {
return fibonacci<N - 1>() + fibonacci<N - 2>();
}
}
// int main() {
// static_assert(fibonacci<1LL>() == 1);
// // static_assert(factorial<3>() == 6);
// // static_assert(factorial<5>() == 120);
//
// // fibonacci<-3>();
//
// return 0;
// }
#include <iostream>
template <typename T>
T add(T x, T y) {
return x + y;
}
template <typename T>
T mult(T t, int N) {
return t * N;
}
int main() {
std::cout << add(2, 3) << '\n';
std::cout << add(1.2, 3.4) << '\n';
std::cout << mult(2, 3) << '\n';
std::cout << mult(1.2, 3) << '\n';
return 0;
}

50
perf-cpp/scripts/ch15.cc Normal file
View file

@ -0,0 +1,50 @@
/*
Question #1
Write a class template named Triad that has 3 private data members with
independent type template parameters. The class should have a constructor,
access functions, and a print() member function that is defined outside the
class.
The following program should compile and run:
*/
#include <iostream>
#include <string>
template <typename T1, typename T2, typename T3>
class Triad {
private:
T1 t1;
T2 t2;
T3 t3;
public:
explicit Triad() {
}
explicit Triad(T1 t1, T2 t2, T3 t3) : t1(t1), t2(t2), t3(t3) {
}
T1 first() { return t1; }
void print() ;
~Triad() {
}
};
template <typename T1, typename T2, typename T3>
void Triad<T1, T2, T3>::print() {
std::cout << '[' << t1 << ", " << t2 << ", " << t3 << "]\n";
}
int main() {
Triad t1{1, 2, 3};
t1.print();
std::cout << '\n';
std::cout << t1.first() << '\n';
using namespace std::literals::string_literals;
const Triad t2{1, 2.3, "Hello"s};
t2.print();
std::cout << '\n';
return 0;
}

38
perf-cpp/scripts/ch4.cc Normal file
View file

@ -0,0 +1,38 @@
/*
Write the following program: The user is asked to enter 2 floating point numbers (use doubles). The user is then asked to enter one of the following mathematical symbols: +, -, *, or /. The program computes the answer on the two numbers the user entered and prints the results. If the user enters an invalid symbol, the program should print nothing.
*/
#include <iostream>
int main() {
double x, y;
std::cout << "enter x: "<<'\n';
std::cin >> x;
std::cout << "enter x: "<<'\n';
std::cin >> y;
std::cout << "enter symbol " << '\n';;
char symbol;
std::cin >> symbol;
double ans;
switch (symbol) {
case '+':
ans = x + y;
break;
case '-':
ans = x - y;
break;
case '*':
ans = x * y;
break;
case '/':
ans = x / y;
break;
default:
return 0;
}
std::cout << "answer: " << ans << '\n';
return 0;
}

51
perf-cpp/scripts/ch5.cc Normal file
View file

@ -0,0 +1,51 @@
#include <cassert>
#include <cmath>
#include <concepts>
#include <iomanip>
#include <iostream>
#include <string>
#include <string_view>
template <std::integral T>
T binexp(T base, T exponent, T mod) {
assert(mod > 0 && exponent > 0);
T product{1};
T multiplier{base % mod};
while (exponent > 0) {
if ((exponent & 1) != 0) {
product = (multiplier * product) % mod;
}
multiplier = (multiplier * multiplier) % mod;
exponent >>= 1;
}
return product;
}
int main() {
using namespace std::string_view_literals;
std::string S{"hello"};
std::string_view s{S};
S.~basic_string();
// double ub - free + string view dereferencing destroyed object
// std::cout << s << '\n' ;
std::cout << -5 / 2 << '\n';
using namespace std;
long double ld = pow((long double)10, 18); // computed in floating point
long long ll = (long long)ld; // cast back to integer
cout << fixed << setprecision(0);
cout << "pow(10,18) as long double: " << ld << "\n";
cout << "cast to long long: " << ll << "\n";
cout << "Should be exactly: " << 1000000000000000000LL << "\n";
std::cout << binexp(2, 5, 5);
return 0;
}

20
perf-cpp/scripts/ch6.cc Normal file
View file

@ -0,0 +1,20 @@
#include <iostream>
#include <cstdint>
/*
Write a program that asks the user to input an integer, and tells the user whether the number is even or odd. Write a constexpr function called isEven() that returns true if an integer passed to it is even, and false otherwise. Use the remainder operator to test whether the integer parameter is even. Make sure isEven() works with both positive and negative numbers
.*/
constexpr bool isEven(std::int32_t number) {
return number % 2 == 0;
}
int main() {
std::cout << "input an integer: \n";
std::int32_t x{};
std::cin >> x;
std::cout << std::boolalpha << isEven(x);
return 0;
}

View file

@ -0,0 +1,18 @@
#include <iostream>
int main() {
std::cout << "Enter a number: \n";
int n;
std::cin >> n;
int m;
std::cout << "Enter another number: \n";
std::cin >> m;
std::cout << "Diff: " << n - m << "; Sum: " << n + m << '\n';
return 0;
}

View file

@ -0,0 +1,2 @@
-O0
-std=c++20

View file

@ -0,0 +1,14 @@
#include <iostream>
consteval int foo(int x) {
if (x <= 1) return x;
return foo(x - 1) + foo(x - 2);
}
int main() {
constexpr int x = foo(3);
static_assert(x != foo(4));
return 0;
}

View file

@ -0,0 +1,10 @@
#include <iostream>
void f(double) { std::cout << "double\n"; }
void f(int) { std::cout << "long\n"; }
int main() {
short x = 5;
f(x); // Which one?
}

View file

@ -0,0 +1,14 @@
-g3
-fsanitize=address,undefined
-fsanitize=float-divide-by-zero
-fsanitize=float-cast-overflow
-fno-sanitize-recover=all
-fstack-protector-all
-fstack-usage
-fno-omit-frame-pointer
-fno-inline
-ffunction-sections
-D_GLIBCXX_DEBUG
-D_GLIBCXX_DEBUG_PEDANTIC
-DLOCAL
-std=c++23

View file

@ -0,0 +1,50 @@
#include <iostream>
struct Counter {
inline static int x = 1;
static void bump() { ++x; }
};
struct Counter2 : Counter {
inline static int x = 100;
static void bump() { x += 10; }
};
enum E { A = 1, B = 2 };
struct S {
enum E { B = 3, C = 4 };
static int f() { return B; }
};
enum class M : unsigned char { A = 250, B, C };
int g() {
int B = 40;
return S::f() + B;
}
int main() {
Counter::bump();
Counter2::bump();
// 112
int t1 = Counter::x + Counter2::x;
// 43
int u1 = g();
int B = 7;
// 9
int t2 = B + ::B;
int d;
{
using enum M;
// 251 - 250 = 1?
d = static_cast<int>(B) - static_cast<int>(A);
}
std::cout << t1 << " " << u1 << " " << t2 << " " << d << "\n";
}

View file

@ -0,0 +1,2 @@
1
2

View file

@ -0,0 +1,7 @@
Enter a number:
Enter another number:
Diff: -1; Sum: 3
[code]: 0
[time]: 2.52771 ms
[debug]: false

View file

View file

@ -0,0 +1,14 @@
file.cc: In function int main():
file.cc:66:23: error: narrowing conversion of 3.0e+0 from double to int [-Wnarrowing]
66 | vector<int> a= { 3.0};
| ^
file.cc: At global scope:
file.cc:39:13: warning: void YES() defined but not used [-Wunused-function]
39 | static void YES() {
| ^~~
file.cc:35:13: warning: void NO() defined but not used [-Wunused-function]
35 | static void NO() {
| ^~
cc1plus: note: unrecognized command-line option -Wno-sign-promotion may have been intended to silence earlier diagnostics
[code]: 1

32
perf-cpp/scripts/loops.cc Normal file
View file

@ -0,0 +1,32 @@
#include <iostream>
void call_for() {
for (int i = 0; i < 5; ++i) {
std::cout << (1 + 123 * 6 ^ 3 << 2);
}
}
void call_while() {
int i = 0;
while (i < 5) {
std::cout << (1 + 123 * 6 ^ 3 << 2);
++i;
}
}
void call_do_while() {
int i = 0;
do {
std::cout << (1 + 123 * 6 ^ 3 << 2);
++i;
} while (i < 5);
}
int main() {
call_for();
call_while();
call_do_while();
return 0;
}

30
perf-cpp/scripts/makefile Normal file
View file

@ -0,0 +1,30 @@
.PHONY: run debug clean setup init
VERSION ?= 20
SRC = $(word 2,$(MAKECMDGOALS))
.SILENT:
run:
sh scripts/run.sh $(SRC)
debug:
sh scripts/debug.sh $(SRC)
clean:
rm -rf build/*
setup:
test -d build || mkdir -p build
test -d io || mkdir -p io
test -d scripts || mkdir -p scripts
test -f .clang-format || cp $(HOME)/.config/cp-template/.clang-format .
test -f compile_flags.txt || cp $(HOME)/.config/cp-template/compile_flags.txt . && echo -std=c++$(VERSION) >>compile_flags.txt
test -f .clangd || cp $(HOME)/.config/cp-template/.clangd . && echo -e "\t\t-std=c++$(VERSION)" >>.clangd
init:
make setup
%:
@:

View file

@ -0,0 +1,29 @@
#!/bin/sh
. ./scripts/utils.sh
SRC="$1"
BASE=$(basename "$SRC" .cc)
INPUT="${BASE}.in"
OUTPUT="${BASE}.out"
DBG_BIN="${BASE}.debug"
test -d build || mkdir -p build
test -d io || mkdir -p io
test -f "$INPUT" && test ! -f "io/$INPUT" && mv "$INPUT" "io/"
test -f "$OUTPUT" && test ! -f "io/$OUTPUT" && mv "$OUTPUT" "io/"
test -f "io/$INPUT" || touch "io/$INPUT"
test -f "io/$OUTPUT" || touch "io/$OUTPUT"
INPUT="io/$INPUT"
OUTPUT="io/$OUTPUT"
DBG_BIN="build/$DBG_BIN"
compile_source "$SRC" "$DBG_BIN" "$OUTPUT" @debug_flags.txt
CODE=$?
test $CODE -gt 0 && exit $CODE
execute_binary "$DBG_BIN" "$INPUT" "$OUTPUT" true
exit $?

View file

@ -0,0 +1,29 @@
#!/bin/sh
. ./scripts/utils.sh
SRC="$1"
BASE=$(basename "$SRC" .cc)
INPUT="${BASE}.in"
OUTPUT="${BASE}.out"
RUN_BIN="${BASE}.run"
test -d build || mkdir -p build
test -d io || mkdir -p io
test -f "$INPUT" && test ! -f "io/$INPUT" && mv "$INPUT" "io/"
test -f "$OUTPUT" && test ! -f "io/$OUTPUT" && mv "$OUTPUT" "io/"
test -f "io/$INPUT" || touch "io/$INPUT"
test -f "io/$OUTPUT" || touch "io/$OUTPUT"
INPUT="io/$INPUT"
OUTPUT="io/$OUTPUT"
RUN_BIN="build/$RUN_BIN"
compile_source "$SRC" "$RUN_BIN" "$OUTPUT" ""
CODE=$?
test $CODE -gt 0 && exit $CODE
execute_binary "$RUN_BIN" "$INPUT" "$OUTPUT"
exit $?

View file

@ -0,0 +1,61 @@
#!/bin/sh
execute_binary() {
binary="$1"
input="$2"
output="$3"
is_debug="$4"
start=$(date '+%s.%N')
if [ -n "$is_debug" ]; then
asan="$(ldconfig -p | grep libasan.so | head -n1 | awk '{print $4}')"
LD_PRELOAD="$asan" timeout 2s ./"$binary" <"$input" >"$output" 2>&1
else
timeout 2s ./"$binary" <"$input" >"$output" 2>&1
fi
CODE=$?
end=$(date '+%s.%N')
truncate -s "$(head -n 1000 "$output" | wc -c)" "$output"
if [ $CODE -ge 124 ]; then
MSG=''
case $CODE in
124) MSG='TIMEOUT' ;;
128) MSG='SIGILL' ;;
130) MSG='SIGABRT' ;;
131) MSG='SIGBUS' ;;
136) MSG='SIGFPE' ;;
135) MSG='SIGSEGV' ;;
137) MSG='SIGPIPE' ;;
139) MSG='SIGTERM' ;;
esac
[ $CODE -ne 124 ] && sed -i '$d' "$output"
test -n "$MSG" && printf '\n[code]: %s (%s)' "$CODE" "$MSG" >>"$output"
else
printf '\n[code]: %s' "$CODE" >>"$output"
fi
printf '\n[time]: %s ms' "$(awk "BEGIN {print ($end - $start) * 1000}")" >>$output
test -n "$is_debug" && is_debug_string=true || is_debug_string=false
printf '\n[debug]: %s' "$is_debug_string" >>$output
return $CODE
}
compile_source() {
src="$1"
bin="$2"
output="$3"
flags="$4"
test -f "$bin" && rm "$bin" || true
g++ @compile_flags.txt $flags "$src" -o "$bin" 2>"$output"
CODE=$?
if [ $CODE -gt 0 ]; then
printf '\n[code]: %s' "$CODE" >>"$output"
return $CODE
else
echo '' >"$output"
return 0
fi
}

View file

@ -0,0 +1,40 @@
#include <iostream>
class S {
// void print() const { a = 3; std::cout << S::a << '\n'; }
int a = 0;
public:
S(int x) : x(x) {
}
int x{2};
};
class X {
int x;
public:
X() : x(0) {};
void get() {
std::cout << "x; " << x << '\n';
}
int& y() {
return x;
}
};
int main() {
// S{}.print();
// S.x;
// std::cout << S{3}.x << '\n';
X x;
auto& ret = x.y();
// ++ret;
x.get();
// X x;
return 0;
}

View file

@ -0,0 +1,39 @@
#include <iostream>
extern volatile int sink;
int g(int x) {
if (x == 100) sink = 42;
else if (x == 101) sink = 7;
else if (x == 102) sink = 99;
else if (x == 103) sink = 13;
else if (x == 104) sink = 5;
else if (x == 105) sink = 88;
else if (x == 106) sink = 21;
else if (x == 107) sink = 60;
else if (x == 108) sink = 33;
else if (x == 109) sink = 1;
else if (x == 110) sink = 77;
else if (x == 111) sink = 12;
else if (x == 112) sink = 54;
else if (x == 113) sink = 31;
else if (x == 114) sink = 73;
else if (x == 115) sink = 16;
else sink = -1;
return sink;
}
int main() {
char x;
std::cin >> x;
if (x == 'x') {
std::cout << "hi\n";
} else {
if (x == 'y') {
std::cout << "sup\n";
}
}
return 0;
}