github.com/grailbio/base@v0.0.11/stress/oom/oom.go (about) 1 // Copyright 2019 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd linux openbsd solaris netbsd 6 7 // Package oom contains a single function to trigger Linux kernel OOMs. 8 package oom 9 10 import ( 11 "bufio" 12 "log" 13 "os" 14 "strconv" 15 "strings" 16 17 "golang.org/x/sys/unix" 18 ) 19 20 // Do attempts to OOM the process by allocating up 21 // to the provided number of bytes. Do never returns. 22 func Do(size int) { 23 log.Print("oom: allocating ", size, " bytes") 24 var ( 25 prot = unix.PROT_READ | unix.PROT_WRITE 26 flag = unix.MAP_PRIVATE | unix.MAP_ANON | unix.MAP_NORESERVE 27 ) 28 b, err := unix.Mmap(-1, 0, size, prot, flag) 29 if err != nil { 30 log.Fatal(err) 31 } 32 stride := os.Getpagesize() 33 // Touch each page so that the process gradually allocates 34 // more and more memory. 35 for i := 0; i < size; i += stride { 36 b[i] = 1 37 } 38 log.Fatal("failed to OOM process") 39 } 40 41 // Try attempts to OOM based on the available physical memory and 42 // default overcommit heuristics. Try never returns. 43 func Try() { 44 f, err := os.Open("/proc/meminfo") 45 if err != nil { 46 log.Fatal(err) 47 } 48 scan := bufio.NewScanner(f) 49 for scan.Scan() { 50 fields := strings.Fields(scan.Text()) 51 if len(fields) < 2 { 52 continue 53 } 54 if fields[0] != "MemTotal:" { 55 continue 56 } 57 if fields[2] != "kB" { 58 log.Fatalf("expected kilobytes, got %s", fields[2]) 59 } 60 kb, err := strconv.ParseInt(fields[1], 0, 64) 61 if err != nil { 62 log.Fatalf("parsing %q: %v", fields[2], err) 63 } 64 Do(int(kb << 10)) 65 } 66 if err := scan.Err(); err != nil { 67 log.Fatal(err) 68 } 69 log.Fatal("MemTotal not found in /proc/meminfo") 70 }