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  }