#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.

unset LANG
export LC_ALL=C
export LC_CTYPE=C

if test -z "$GOARCH" -o -z "$GOOS"; then
	echo 1>&2 "GOARCH or GOOS not defined in environment"
	exit 1
fi

# Check that we are using the new build system if we should
if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
	echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
	echo 1>&2 "See README.md"
	exit 1
fi

if [[ "$GOOS" = "aix" ]]; then
	CC=${CC:-gcc}
else
	CC=${CC:-cc}
fi

if [[ "$GOOS" = "solaris" ]]; then
	# Assumes GNU versions of utilities in PATH.
	export PATH=/usr/gnu/bin:$PATH
fi

uname=$(uname)

includes_AIX='
#include <net/if.h>
#include <net/netopt.h>
#include <netinet/ip_mroute.h>
#include <sys/protosw.h>
#include <sys/stropts.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/termio.h>
#include <termios.h>
#include <fcntl.h>

#define AF_LOCAL AF_UNIX
'

includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL 1
#define _DARWIN_USE_64_BIT_INODE
#define __APPLE_USE_RFC_3542
#include <stdint.h>
#include <sys/attr.h>
#include <sys/clonefile.h>
#include <sys/kern_control.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/ptrace.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/sockio.h>
#include <sys/sys_domain.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <sys/vsock.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <termios.h>

// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk.
#define TIOCREMOTE 0x80047469
'

includes_DragonFly='
#include <sys/types.h>
#include <sys/event.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <net/ip_mroute/ip_mroute.h>
'

includes_FreeBSD='
#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/disk.h>
#include <sys/event.h>
#include <sys/sched.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <sys/extattr.h>

#if __FreeBSD__ >= 10
#define IFT_CARP	0xf8	// IFT_CARP is deprecated in FreeBSD 10
#undef SIOCAIFADDR
#define SIOCAIFADDR	_IOW(105, 26, struct oifaliasreq)	// ifaliasreq contains if_data
#undef SIOCSIFPHYADDR
#define SIOCSIFPHYADDR	_IOW(105, 70, struct oifaliasreq)	// ifaliasreq contains if_data
#endif
'

includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef __LP64__
#define _FILE_OFFSET_BITS 64
#endif
#define _GNU_SOURCE

// <sys/ioctl.h> is broken on powerpc64, as it fails to include definitions of
// these structures. We just include them copied from <bits/termios.h>.
#if defined(__powerpc__)
struct sgttyb {
        char    sg_ispeed;
        char    sg_ospeed;
        char    sg_erase;
        char    sg_kill;
        short   sg_flags;
};

struct tchars {
        char    t_intrc;
        char    t_quitc;
        char    t_startc;
        char    t_stopc;
        char    t_eofc;
        char    t_brkc;
};

struct ltchars {
        char    t_suspc;
        char    t_dsuspc;
        char    t_rprntc;
        char    t_flushc;
        char    t_werasc;
        char    t_lnextc;
};
#endif

#include <bits/sockaddr.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/uio.h>
#include <sys/xattr.h>
#include <netinet/udp.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/netlink.h>
#include <linux/can/raw.h>
#include <linux/capability.h>
#include <linux/cryptouser.h>
#include <linux/devlink.h>
#include <linux/dm-ioctl.h>
#include <linux/errqueue.h>
#include <linux/ethtool_netlink.h>
#include <linux/falloc.h>
#include <linux/fanotify.h>
#include <linux/fib_rules.h>
#include <linux/filter.h>
#include <linux/fs.h>
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/genetlink.h>
#include <linux/hdreg.h>
#include <linux/hidraw.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_alg.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_ppp.h>
#include <linux/if_tun.h>
#include <linux/if_packet.h>
#include <linux/if_xdp.h>
#include <linux/input.h>
#include <linux/kcm.h>
#include <linux/kexec.h>
#include <linux/keyctl.h>
#include <linux/landlock.h>
#include <linux/loop.h>
#include <linux/lwtunnel.h>
#include <linux/magic.h>
#include <linux/memfd.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <linux/net_namespace.h>
#include <linux/nfc.h>
#include <linux/nsfs.h>
#include <linux/perf_event.h>
#include <linux/pps.h>
#include <linux/ptrace.h>
#include <linux/random.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/rtnetlink.h>
#include <linux/sched.h>
#include <linux/seccomp.h>
#include <linux/serial.h>
#include <linux/sockios.h>
#include <linux/taskstats.h>
#include <linux/tipc.h>
#include <linux/vm_sockets.h>
#include <linux/wait.h>
#include <linux/watchdog.h>
#include <linux/wireguard.h>

#include <mtd/ubi-user.h>
#include <mtd/mtd-user.h>
#include <net/route.h>

#if defined(__sparc__)
// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
// definition in glibc. As only the error constants are needed here, include the
// generic termibits.h (which is included by termbits.h on sparc).
#include <asm-generic/termbits.h>
#else
#include <asm/termbits.h>
#endif

#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN    0x20000000
#endif

#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS	0xc
#endif

#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS	0xd
#endif

#ifndef SOL_NETLINK
#define SOL_NETLINK	270
#endif

#ifndef SOL_SMC
#define SOL_SMC 286
#endif

#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
#undef SOL_BLUETOOTH
#endif

// Certain constants are missing from the fs/crypto UAPI
#define FS_KEY_DESC_PREFIX              "fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE         8
#define FS_MAX_KEY_SIZE                 64

// The code generator produces -0x1 for (~0), but an unsigned value is necessary
// for the tipc_subscr timeout __u32 field.
#undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff

// Copied from linux/l2tp.h
// Including linux/l2tp.h here causes conflicts between linux/in.h
// and netinet/in.h included via net/route.h above.
#define IPPROTO_L2TP		115

// Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields.
#define _HIDIOCGRAWNAME_LEN	128 // sizeof_field(struct hid_device, name)
#define _HIDIOCGRAWPHYS_LEN	64  // sizeof_field(struct hid_device, phys)
#define _HIDIOCGRAWUNIQ_LEN	64  // sizeof_field(struct hid_device, uniq)

#define _HIDIOCGRAWNAME		HIDIOCGRAWNAME(_HIDIOCGRAWNAME_LEN)
#define _HIDIOCGRAWPHYS		HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
#define _HIDIOCGRAWUNIQ		HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)

'

includes_NetBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
#include <sys/extattr.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/sched.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/termios.h>
#include <sys/ttycom.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>

// Needed since <sys/param.h> refers to it...
#define schedppq 1
'

includes_OpenBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/select.h>
#include <sys/sched.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/termios.h>
#include <sys/ttycom.h>
#include <sys/unistd.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>
#include <net/if_bridge.h>

// We keep some constants not supported in OpenBSD 5.5 and beyond for
// the promise of compatibility.
#define EMUL_ENABLED		0x1
#define EMUL_NATIVE		0x2
#define IPV6_FAITH		0x1d
#define IPV6_OPTIONS		0x1
#define IPV6_RTHDR_STRICT	0x1
#define IPV6_SOCKOPT_RESERVED1	0x3
#define SIOCGIFGENERIC		0xc020693a
#define SIOCSIFGENERIC		0x80206939
#define WALTSIG			0x4
'

includes_SunOS='
#include <limits.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/stream.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/mkdev.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <termios.h>
'

includes='
#include <sys/types.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/signal.h>
#include <signal.h>
#include <sys/resource.h>
#include <time.h>
'
ccflags="$@"

# Write go tool cgo -godefs input.
(
	echo package unix
	echo
	echo '/*'
	indirect="includes_$(uname)"
	echo "${!indirect} $includes"
	echo '*/'
	echo 'import "C"'
	echo 'import "syscall"'
	echo
	echo 'const ('

	# The gcc command line prints all the #defines
	# it encounters while processing the input
	echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
	awk '
		$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}

		$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next}  # 386 registers
		$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
		$2 ~ /^(SCM_SRCRT)$/ {next}
		$2 ~ /^(MAP_FAILED)$/ {next}
		$2 ~ /^ELF_.*$/ {next}# <asm/elf.h> contains ELF_ARCH, etc.

		$2 ~ /^EXTATTR_NAMESPACE_NAMES/ ||
		$2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next}

		$2 !~ /^ECCAPBITS/ &&
		$2 !~ /^ETH_/ &&
		$2 !~ /^EPROC_/ &&
		$2 !~ /^EQUIV_/ &&
		$2 !~ /^EXPR_/ &&
		$2 !~ /^EVIOC/ &&
		$2 ~ /^E[A-Z0-9_]+$/ ||
		$2 ~ /^B[0-9_]+$/ ||
		$2 ~ /^(OLD|NEW)DEV$/ ||
		$2 == "BOTHER" ||
		$2 ~ /^CI?BAUD(EX)?$/ ||
		$2 == "IBSHIFT" ||
		$2 ~ /^V[A-Z0-9]+$/ ||
		$2 ~ /^CS[A-Z0-9]/ ||
		$2 ~ /^I(SIG|CANON|CRNL|UCLC|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
		$2 ~ /^IGN/ ||
		$2 ~ /^IX(ON|ANY|OFF)$/ ||
		$2 ~ /^IN(LCR|PCK)$/ ||
		$2 !~ "X86_CR3_PCID_NOFLUSH" &&
		$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
		$2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ ||
		$2 == "BRKINT" ||
		$2 == "HUPCL" ||
		$2 == "PENDIN" ||
		$2 == "TOSTOP" ||
		$2 == "XCASE" ||
		$2 == "ALTWERASE" ||
		$2 == "NOKERNINFO" ||
		$2 == "NFDBITS" ||
		$2 ~ /^PAR/ ||
		$2 ~ /^SIG[^_]/ ||
		$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
		$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
		$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
		$2 ~ /^O?XTABS$/ ||
		$2 ~ /^TC[IO](ON|OFF)$/ ||
		$2 ~ /^IN_/ ||
		$2 ~ /^KCM/ ||
		$2 ~ /^LANDLOCK_/ ||
		$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
		$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
		$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
		$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
		$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
		$2 ~ /^RAW_PAYLOAD_/ ||
		$2 ~ /^[US]F_/ ||
		$2 ~ /^TP_STATUS_/ ||
		$2 ~ /^FALLOC_/ ||
		$2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
		$2 == "SOMAXCONN" ||
		$2 == "NAME_MAX" ||
		$2 == "IFNAMSIZ" ||
		$2 ~ /^CTL_(HW|KERN|MAXNAME|NET|QUERY)$/ ||
		$2 ~ /^KERN_(HOSTNAME|OS(RELEASE|TYPE)|VERSION)$/ ||
		$2 ~ /^HW_MACHINE$/ ||
		$2 ~ /^SYSCTL_VERS/ ||
		$2 !~ "MNT_BITS" &&
		$2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ ||
		$2 ~ /^NS_GET_/ ||
		$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
		$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|PIOD|TFD)_/ ||
		$2 ~ /^KEXEC_/ ||
		$2 ~ /^LINUX_REBOOT_CMD_/ ||
		$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
		$2 ~ /^MODULE_INIT_/ ||
		$2 !~ "NLA_TYPE_MASK" &&
		$2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ &&
		$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
		$2 ~ /^FIORDCHK$/ ||
		$2 ~ /^SIOC/ ||
		$2 ~ /^TIOC/ ||
		$2 ~ /^TCGET/ ||
		$2 ~ /^TCSET/ ||
		$2 ~ /^TC(FLSH|SBRKP?|XONC)$/ ||
		$2 !~ "RTF_BITS" &&
		$2 ~ /^(IFF|IFT|NET_RT|RTM(GRP)?|RTF|RTV|RTA|RTAX)_/ ||
		$2 ~ /^BIOC/ ||
		$2 ~ /^DIOC/ ||
		$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
		$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ ||
		$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
		$2 ~ /^CLONE_[A-Z_]+/ ||
		$2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ &&
		$2 ~ /^(BPF|DLT)_/ ||
		$2 ~ /^AUDIT_/ ||
		$2 ~ /^(CLOCK|TIMER)_/ ||
		$2 ~ /^CAN_/ ||
		$2 ~ /^CAP_/ ||
		$2 ~ /^CP_/ ||
		$2 ~ /^CPUSTATES$/ ||
		$2 ~ /^CTLIOCGINFO$/ ||
		$2 ~ /^ALG_/ ||
		$2 ~ /^FI(CLONE|DEDUPERANGE)/ ||
		$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ ||
		$2 ~ /^FS_IOC_.*(ENCRYPTION|VERITY|[GS]ETFLAGS)/ ||
		$2 ~ /^FS_VERITY_/ ||
		$2 ~ /^FSCRYPT_/ ||
		$2 ~ /^DM_/ ||
		$2 ~ /^GRND_/ ||
		$2 ~ /^RND/ ||
		$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
		$2 ~ /^KEYCTL_/ ||
		$2 ~ /^PERF_/ ||
		$2 ~ /^SECCOMP_MODE_/ ||
		$2 ~ /^SEEK_/ ||
		$2 ~ /^SPLICE_/ ||
		$2 ~ /^SYNC_FILE_RANGE_/ ||
		$2 !~ /IOC_MAGIC/ &&
		$2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
		$2 ~ /^(VM|VMADDR)_/ ||
		$2 ~ /^IOCTL_VM_SOCKETS_/ ||
		$2 ~ /^(TASKSTATS|TS)_/ ||
		$2 ~ /^CGROUPSTATS_/ ||
		$2 ~ /^GENL_/ ||
		$2 ~ /^STATX_/ ||
		$2 ~ /^RENAME/ ||
		$2 ~ /^UBI_IOC[A-Z]/ ||
		$2 ~ /^UTIME_/ ||
		$2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ ||
		$2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ ||
		$2 ~ /^FSOPT_/ ||
		$2 ~ /^WDIO[CFS]_/ ||
		$2 ~ /^NFN/ ||
		$2 ~ /^XDP_/ ||
		$2 ~ /^RWF_/ ||
		$2 ~ /^(HDIO|WIN|SMART)_/ ||
		$2 ~ /^CRYPTO_/ ||
		$2 ~ /^TIPC_/ ||
		$2 !~  "DEVLINK_RELOAD_LIMITS_VALID_MASK" &&
		$2 ~ /^DEVLINK_/ ||
		$2 ~ /^ETHTOOL_/ ||
		$2 ~ /^LWTUNNEL_IP/ ||
		$2 ~ /^ITIMER_/ ||
		$2 !~ "WMESGLEN" &&
		$2 ~ /^W[A-Z0-9]+$/ ||
		$2 ~ /^P_/ ||
		$2 ~/^PPPIOC/ ||
		$2 ~ /^FAN_|FANOTIFY_/ ||
		$2 == "HID_MAX_DESCRIPTOR_SIZE" ||
		$2 ~ /^_?HIDIOC/ ||
		$2 ~ /^BUS_(USB|HIL|BLUETOOTH|VIRTUAL)$/ ||
		$2 ~ /^MTD/ ||
		$2 ~ /^OTP/ ||
		$2 ~ /^MEM/ ||
		$2 ~ /^WG/ ||
		$2 ~ /^FIB_RULE_/ ||
		$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
		$2 ~ /^__WCOREFLAG$/ {next}
		$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}

		{next}
	' | sort

	echo ')'
) >_const.go

# Pull out the error names for later.
errors=$(
	echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
	sort
)

# Pull out the signal names for later.
signals=$(
	echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
	sort
)

# Again, writing regexps to a file.
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
	sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
	sort >_signal.grep

echo '// mkerrors.sh' "$@"
echo '// Code generated by the command above; see README.md. DO NOT EDIT.'
echo
echo "//go:build ${GOARCH} && ${GOOS}"
echo "// +build ${GOARCH},${GOOS}"
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
echo
echo '// Errors'
echo 'const ('
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= syscall.Errno(\1)/'
echo ')'

echo
echo '// Signals'
echo 'const ('
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= syscall.Signal(\1)/'
echo ')'

# Run C program to print error and syscall strings.
(
	echo -E "
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>

#define nelem(x) (sizeof(x)/sizeof((x)[0]))

enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below

struct tuple {
	int num;
	const char *name;
};

struct tuple errors[] = {
"
	for i in $errors
	do
		echo -E '	{'$i', "'$i'" },'
	done

	echo -E "
};

struct tuple signals[] = {
"
	for i in $signals
	do
		echo -E '	{'$i', "'$i'" },'
	done

	# Use -E because on some systems bash builtin interprets \n itself.
	echo -E '
};

static int
tuplecmp(const void *a, const void *b)
{
	return ((struct tuple *)a)->num - ((struct tuple *)b)->num;
}

int
main(void)
{
	int i, e;
	char buf[1024], *p;

	printf("\n\n// Error table\n");
	printf("var errorList = [...]struct {\n");
	printf("\tnum  syscall.Errno\n");
	printf("\tname string\n");
	printf("\tdesc string\n");
	printf("} {\n");
	qsort(errors, nelem(errors), sizeof errors[0], tuplecmp);
	for(i=0; i<nelem(errors); i++) {
		e = errors[i].num;
		if(i > 0 && errors[i-1].num == e)
			continue;
		strncpy(buf, strerror(e), sizeof(buf) - 1);
		buf[sizeof(buf) - 1] = '\0';
		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
			buf[0] += a - A;
		printf("\t{ %d, \"%s\", \"%s\" },\n", e, errors[i].name, buf);
	}
	printf("}\n\n");

	printf("\n\n// Signal table\n");
	printf("var signalList = [...]struct {\n");
	printf("\tnum  syscall.Signal\n");
	printf("\tname string\n");
	printf("\tdesc string\n");
	printf("} {\n");
	qsort(signals, nelem(signals), sizeof signals[0], tuplecmp);
	for(i=0; i<nelem(signals); i++) {
		e = signals[i].num;
		if(i > 0 && signals[i-1].num == e)
			continue;
		strncpy(buf, strsignal(e), sizeof(buf) - 1);
		buf[sizeof(buf) - 1] = '\0';
		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
			buf[0] += a - A;
		// cut trailing : number.
		p = strrchr(buf, ":"[0]);
		if(p)
			*p = '\0';
		printf("\t{ %d, \"%s\", \"%s\" },\n", e, signals[i].name, buf);
	}
	printf("}\n\n");

	return 0;
}

'
) >_errors.c

$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out


#!/bin/bash
set -e

if [[ $GO111MODULE == "on" ]]; then
  go get .
else
  go get -u -v $(go list -f '{{join .Imports "\n"}}{{"\n"}}{{join .TestImports "\n"}}' ./... | sort | uniq | grep -v appengine)
fi

if [[ $GOAPP == "true" ]]; then
  mkdir /tmp/sdk
  curl -o /tmp/sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip"
  unzip -q /tmp/sdk.zip -d /tmp/sdk
  # NOTE: Set the following env vars in the test script:
  # export PATH="$PATH:/tmp/sdk/go_appengine"
  # export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
fi


#!/bin/bash
set -e

go version
go test -v google.golang.org/appengine/...
go test -v -race google.golang.org/appengine/...
if [[ $GOAPP == "true" ]]; then
  export PATH="$PATH:/tmp/sdk/go_appengine"
  export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
  goapp version
  goapp test -v google.golang.org/appengine/...
fi


#!/bin/bash -e
#
# This script rebuilds the generated code for the protocol buffers.
# To run this you will need protoc and goprotobuf installed;
# see https://github.com/golang/protobuf for instructions.

PKG=google.golang.org/appengine

function die() {
	echo 1>&2 $*
	exit 1
}

# Sanity check that the right tools are accessible.
for tool in go protoc protoc-gen-go; do
	q=$(which $tool) || die "didn't find $tool"
	echo 1>&2 "$tool: $q"
done

echo -n 1>&2 "finding package dir... "
pkgdir=$(go list -f '{{.Dir}}' $PKG)
echo 1>&2 $pkgdir
base=$(echo $pkgdir | sed "s,/$PKG\$,,")
echo 1>&2 "base: $base"
cd $base

# Run protoc once per package.
for dir in $(find $PKG/internal -name '*.proto' | xargs dirname | sort | uniq); do
	echo 1>&2 "* $dir"
	protoc --go_out=. $dir/*.proto
done

for f in $(find $PKG/internal -name '*.pb.go'); do
  # Remove proto.RegisterEnum calls.
  # These cause duplicate registration panics when these packages
  # are used on classic App Engine. proto.RegisterEnum only affects
  # parsing the text format; we don't care about that.
  # https://code.google.com/p/googleappengine/issues/detail?id=11670#c17
  sed -i '/proto.RegisterEnum/d' $f
done


#!/usr/bin/env bash

# This script serves as an example to demonstrate how to generate the gRPC-Go
# interface and the related messages from .proto file.
#
# It assumes the installation of i) Google proto buffer compiler at
# https://github.com/google/protobuf (after v2.6.1) and ii) the Go codegen
# plugin at https://github.com/golang/protobuf (after 2015-02-20). If you have
# not, please install them first.
#
# We recommend running this script at $GOPATH/src.
#
# If this is not what you need, feel free to make your own scripts. Again, this
# script is for demonstration purpose.
#
proto=$1
protoc --go_out=plugins=grpc:. $proto


#!/bin/bash
# Copyright 2020 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -eu -o pipefail

WORKDIR=$(mktemp -d)

function finish {
  rm -rf "$WORKDIR"
}
trap finish EXIT

export GOBIN=${WORKDIR}/bin
export PATH=${GOBIN}:${PATH}
mkdir -p ${GOBIN}

echo "go install github.com/golang/protobuf/protoc-gen-go"
(cd test/tools && go install github.com/golang/protobuf/protoc-gen-go)

echo "go install cmd/protoc-gen-go-grpc"
(cd cmd/protoc-gen-go-grpc && go install .)

echo "git clone https://github.com/grpc/grpc-proto"
git clone --quiet https://github.com/grpc/grpc-proto ${WORKDIR}/grpc-proto

mkdir -p ${WORKDIR}/googleapis/google/rpc
echo "curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/rpc/code.proto"
curl --silent https://raw.githubusercontent.com/googleapis/googleapis/master/google/rpc/code.proto > ${WORKDIR}/googleapis/google/rpc/code.proto

# Pull in the following repos to build the MeshCA config proto.
ENVOY_API_REPOS=(
  "https://github.com/envoyproxy/data-plane-api"
  "https://github.com/cncf/udpa"
  "https://github.com/envoyproxy/protoc-gen-validate"
)
for repo in ${ENVOY_API_REPOS[@]}; do
  dirname=$(basename ${repo})
  mkdir -p ${WORKDIR}/${dirname}
  echo "git clone ${repo}"
  git clone --quiet ${repo} ${WORKDIR}/${dirname}
done

# Pull in the MeshCA service proto.
mkdir -p ${WORKDIR}/istio/istio/google/security/meshca/v1
echo "curl https://raw.githubusercontent.com/istio/istio/master/security/proto/providers/google/meshca.proto"
curl --silent https://raw.githubusercontent.com/istio/istio/master/security/proto/providers/google/meshca.proto > ${WORKDIR}/istio/istio/google/security/meshca/v1/meshca.proto

mkdir -p ${WORKDIR}/out

# Generates legacy gRPC Server symbols in addition to the newer Service symbols
LEGACY_SOURCES=(
  ${WORKDIR}/googleapis/google/rpc/code.proto
  ${WORKDIR}/grpc-proto/grpc/binlog/v1/binarylog.proto
  ${WORKDIR}/grpc-proto/grpc/channelz/v1/channelz.proto
  ${WORKDIR}/grpc-proto/grpc/gcp/altscontext.proto
  ${WORKDIR}/grpc-proto/grpc/gcp/handshaker.proto
  ${WORKDIR}/grpc-proto/grpc/gcp/transport_security_common.proto
  ${WORKDIR}/grpc-proto/grpc/health/v1/health.proto
  ${WORKDIR}/grpc-proto/grpc/lb/v1/load_balancer.proto
  ${WORKDIR}/grpc-proto/grpc/lookup/v1/rls.proto
  ${WORKDIR}/grpc-proto/grpc/lookup/v1/rls_config.proto
  ${WORKDIR}/grpc-proto/grpc/service_config/service_config.proto
  ${WORKDIR}/grpc-proto/grpc/tls/provider/meshca/experimental/config.proto
  ${WORKDIR}/istio/istio/google/security/meshca/v1/meshca.proto
  profiling/proto/service.proto
  reflection/grpc_reflection_v1alpha/reflection.proto
)

# Generates only the new gRPC Service symbols
SOURCES=(
  $(git ls-files --exclude-standard --cached --others "*.proto" | grep -v '^\(profiling/proto/service.proto\|reflection/grpc_reflection_v1alpha/reflection.proto\)$')
)

# These options of the form 'Mfoo.proto=bar' instruct the codegen to use an
# import path of 'bar' in the generated code when 'foo.proto' is imported in
# one of the sources.
OPTS=Mgrpc/service_config/service_config.proto=/internal/proto/grpc_service_config,\
Menvoy/config/core/v3/config_source.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3

for src in ${SOURCES[@]}; do
  echo "protoc ${src}"
  protoc --go_out=${OPTS}:${WORKDIR}/out --go-grpc_out=${OPTS}:${WORKDIR}/out ${src}
done

for src in ${LEGACY_SOURCES[@]}; do
  echo "protoc ${src}"
  protoc --go_out=${OPTS},plugins=grpc:${WORKDIR}/out --go-grpc_out=${OPTS},migration_mode=true:${WORKDIR}/out \
    -I"." \
    -I${WORKDIR}/grpc-proto \
    -I${WORKDIR}/googleapis \
    -I${WORKDIR}/data-plane-api \
    -I${WORKDIR}/udpa \
    -I${WORKDIR}/protoc-gen-validate \
    -I${WORKDIR}/istio \
    ${src}
done

# The go_package option in grpc/lookup/v1/rls.proto doesn't match the
# current location. Move it into the right place.
mkdir -p ${WORKDIR}/out/google.golang.org/grpc/balancer/rls/internal/proto/grpc_lookup_v1
mv ${WORKDIR}/out/google.golang.org/grpc/lookup/grpc_lookup_v1/* ${WORKDIR}/out/google.golang.org/grpc/balancer/rls/internal/proto/grpc_lookup_v1

# grpc_testingv3/testv3.pb.go is not re-generated because it was
# intentionally generated by an older version of protoc-gen-go.
rm ${WORKDIR}/out/google.golang.org/grpc/reflection/grpc_testingv3/*.pb.go

# grpc/service_config/service_config.proto does not have a go_package option.
mv ${WORKDIR}/out/grpc/service_config/service_config.pb.go internal/proto/grpc_service_config

# istio/google/security/meshca/v1/meshca.proto does not have a go_package option.
mkdir -p ${WORKDIR}/out/google.golang.org/grpc/credentials/tls/certprovider/meshca/internal/v1/
mv ${WORKDIR}/out/istio/google/security/meshca/v1/* ${WORKDIR}/out/google.golang.org/grpc/credentials/tls/certprovider/meshca/internal/v1/

cp -R ${WORKDIR}/out/google.golang.org/grpc/* .


#!/bin/bash

set -ex  # Exit on error; debugging enabled.
set -o pipefail  # Fail a pipe if any sub-command fails.

# not makes sure the command passed to it does not exit with a return code of 0.
not() {
  # This is required instead of the earlier (! $COMMAND) because subshells and
  # pipefail don't work the same on Darwin as in Linux.
  ! "$@"
}

die() {
  echo "$@" >&2
  exit 1
}

fail_on_output() {
  tee /dev/stderr | not read
}

# Check to make sure it's safe to modify the user's git repo.
git status --porcelain | fail_on_output

# Undo any edits made by this script.
cleanup() {
  git reset --hard HEAD
}
trap cleanup EXIT

PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"

if [[ "$1" = "-install" ]]; then
  # Check for module support
  if go help mod >& /dev/null; then
    # Install the pinned versions as defined in module tools.
    pushd ./test/tools
    go install \
      golang.org/x/lint/golint \
      golang.org/x/tools/cmd/goimports \
      honnef.co/go/tools/cmd/staticcheck \
      github.com/client9/misspell/cmd/misspell
    popd
  else
    # Ye olde `go get` incantation.
    # Note: this gets the latest version of all tools (vs. the pinned versions
    # with Go modules).
    go get -u \
      golang.org/x/lint/golint \
      golang.org/x/tools/cmd/goimports \
      honnef.co/go/tools/cmd/staticcheck \
      github.com/client9/misspell/cmd/misspell
  fi
  if [[ -z "${VET_SKIP_PROTO}" ]]; then
    if [[ "${TRAVIS}" = "true" ]]; then
      PROTOBUF_VERSION=3.3.0
      PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip
      pushd /home/travis
      wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_FILENAME}
      unzip ${PROTOC_FILENAME}
      bin/protoc --version
      popd
    elif not which protoc > /dev/null; then
      die "Please install protoc into your path"
    fi
  fi
  exit 0
elif [[ "$#" -ne 0 ]]; then
  die "Unknown argument(s): $*"
fi

# - Ensure all source files contain a copyright message.
not git grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" -- '*.go'

# - Make sure all tests in grpc and grpc/test use leakcheck via Teardown.
not grep 'func Test[^(]' *_test.go
not grep 'func Test[^(]' test/*.go

# - Do not import x/net/context.
not git grep -l 'x/net/context' -- "*.go"

# - Do not import math/rand for real library code.  Use internal/grpcrand for
#   thread safety.
git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^stress\|grpcrand\|^benchmark\|wrr_test'

# - Do not call grpclog directly. Use grpclog.Component instead.
git grep -l 'grpclog.I\|grpclog.W\|grpclog.E\|grpclog.F\|grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go'

# - Ensure all ptypes proto packages are renamed when importing.
not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go"

# - Ensure all xds proto imports are renamed to *pb or *grpc.
git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "'

# - gofmt, goimports, golint (with exceptions for generated code), go vet.
gofmt -s -d -l . 2>&1 | fail_on_output
goimports -l . 2>&1 | not grep -vE "\.pb\.go"
golint ./... 2>&1 | not grep -vE "\.pb\.go:"
go vet -all ./...

misspell -error .

# - Check that generated proto files are up to date.
if [[ -z "${VET_SKIP_PROTO}" ]]; then
  PATH="/home/travis/bin:${PATH}" make proto && \
    git status --porcelain 2>&1 | fail_on_output || \
    (git status; git --no-pager diff; exit 1)
fi

# - Check that our modules are tidy.
if go help mod >& /dev/null; then
  find . -name 'go.mod' | xargs -IXXX bash -c 'cd $(dirname XXX); go mod tidy'
  git status --porcelain 2>&1 | fail_on_output || \
    (git status; git --no-pager diff; exit 1)
fi

# - Collection of static analysis checks
#
# TODO(dfawley): don't use deprecated functions in examples or first-party
# plugins.
SC_OUT="$(mktemp)"
staticcheck -go 1.9 -checks 'inherit,-ST1015' ./... > "${SC_OUT}" || true
# Error if anything other than deprecation warnings are printed.
not grep -v "is deprecated:.*SA1019" "${SC_OUT}"
# Only ignore the following deprecated types/fields/functions.
not grep -Fv '.CredsBundle
.HeaderMap
.Metadata is deprecated: use Attributes
.NewAddress
.NewServiceConfig
.Type is deprecated: use Attributes
balancer.ErrTransientFailure
balancer.Picker
grpc.CallCustomCodec
grpc.Code
grpc.Compressor
grpc.CustomCodec
grpc.Decompressor
grpc.MaxMsgSize
grpc.MethodConfig
grpc.NewGZIPCompressor
grpc.NewGZIPDecompressor
grpc.RPCCompressor
grpc.RPCDecompressor
grpc.ServiceConfig
grpc.WithBalancerName
grpc.WithCompressor
grpc.WithDecompressor
grpc.WithDialer
grpc.WithMaxMsgSize
grpc.WithServiceConfig
grpc.WithTimeout
http.CloseNotifier
info.SecurityVersion
resolver.Backend
resolver.GRPCLB' "${SC_OUT}"

# - special golint on package comments.
lint_package_comment_per_package() {
  # Number of files in this go package.
  fileCount=$(go list -f '{{len .GoFiles}}' $1)
  if [ ${fileCount} -eq 0 ]; then
    return 0
  fi
  # Number of package errors generated by golint.
  lintPackageCommentErrorsCount=$(golint --min_confidence 0 $1 | grep -c "should have a package comment")
  # golint complains about every file that's missing the package comment. If the
  # number of files for this package is greater than the number of errors, there's
  # at least one file with package comment, good. Otherwise, fail.
  if [ ${fileCount} -le ${lintPackageCommentErrorsCount} ]; then
    echo "Package $1 (with ${fileCount} files) is missing package comment"
    return 1
  fi
}
lint_package_comment() {
  set +ex

  count=0
  for i in $(go list ./...); do
    lint_package_comment_per_package "$i"
    ((count += $?))
  done

  set -ex
  return $count
}
lint_package_comment

echo SUCCESS


#!/bin/sh

url=$1

wget --quiet --output-document=img.jpg $1
ml ocr azcv img.jpg >| img_bb.txt

# Add bounding boxes to the image.

cat img_bb.txt |
  cut -d',' -f1 |
  xargs printf '-draw "polygon %s,%s %s,%s %s,%s %s,%s" ' |
  awk '{print "img.jpg -fill none -stroke red -strokewidth 5 " $0 "img_bb.jpg"}' |
  xargs convert

# Add the identified text to the image.

cat img_bb.txt |
  tr ',' ' '|
  cut -d' ' -f1,2,9- |
  perl -pe 's|([\d\.]+) ([\d\.]+) (.+)|-annotate +\1+\2 \\"\3\\"|' |
  xargs |
  awk '{print "img_bb.jpg -stroke white -pointsize 30 " $0 " img_bb_text.jpg"}' |
  xargs convert

# Create a montage of the original and final image.

montage -background '#336699' -geometry +4+4 img.jpg img_bb_text.jpg montage.jpg

# Display the image.

eog montage.jpg

# Cleanup

# rm img.jpg img_bb.txt img_bb.jpg img_bb_text.jpg


#!/bin/sh

# ml brands azcv gray-shirt-logo.jpg > brands_bb.txt

arrow_head="l -15,-5  +5,+5  -5,+5  +15,-5 z"

convert -size 100x30 xc: -draw 'stroke skyblue fill skyblue rectangle 30,14 70,16' \
        -draw "stroke skyblue fill skyblue path 'M 70,15  $arrow_head' " \
	arrow_horizontal.png

cat brands_bb.txt |
  cut -d',' -f1 |
  xargs printf '-draw "rectangle %s,%s %s,%s" ' |
  awk '{print "gray-shirt-logo.jpg -fill none -stroke blue -strokewidth 3 " $0 "brands_tmp.png"}' |
  xargs convert

# Combine

convert gray-shirt-logo.jpg arrow_horizontal.png brands_tmp.png -gravity Center +append -resize 70% -bordercolor White -border 10x10 brands_bb.png

eom brands_bb.png


#!/bin/sh

img=$1
dest=$2

accent="#"$(ml color azcv $1 | cut -d, -f2)

convert -size 100x30 xc: -draw "stroke $accent fill $accent rectangle 30,10 90,20" -gravity North -pointsize 10 -annotate 0 "$accent" \
	color_accent.png

convert $1 color_accent.png -gravity Center +append -bordercolor White -border 10x10 $dest

eom $dest


#!/bin/sh

# ml faces azcv faces.jpg > faces_bb.txt

arrow_head="l -15,-5  +5,+5  -5,+5  +15,-5 z"

convert -size 100x30 xc: -draw 'stroke skyblue fill skyblue rectangle 30,14 70,16' \
        -draw "stroke skyblue fill skyblue path 'M 70,15  $arrow_head' " \
	arrow_horizontal.png

cat faces_bb.txt |
  cut -d, -f1 |
  xargs printf '-draw "rectangle %s,%s %s,%s" ' |
  awk '{print "faces.jpg -fill none -stroke blue -strokewidth 3 " $0 "faces_tmp.png"}' |
  xargs convert

# Combine

convert faces.jpg arrow_horizontal.png faces_tmp.png -gravity Center +append -resize 30% -bordercolor White -border 10x10 faces_bb.png

eom faces_bb.png


#!/bin/sh

# ml objects azcv objects.jpg > objects_bb.txt

arrow_head="l -15,-5  +5,+5  -5,+5  +15,-5 z"

convert -size 100x30 xc: -draw 'stroke skyblue fill skyblue rectangle 30,14 70,16' \
        -draw "stroke skyblue fill skyblue path 'M 70,15  $arrow_head' " \
	arrow_horizontal.png

cat objects_bb.txt |
  xargs printf '-draw "rectangle %s,%s %s,%s" ' |
  awk '{print "objects.jpg -fill none -stroke blue -strokewidth 3 " $0 "objects_tmp.png"}' |
  xargs convert

# Combine

convert objects.jpg arrow_horizontal.png objects_tmp.png -gravity Center +append -resize 30% -bordercolor White -border 10x10 objects_bb.png

eom objects_bb.png


#!/bin/sh

if [ "$#" -ne 3 ]; then
  echo "Three parameters are required: orig.png thumb.png dest.png"
  exit
fi

orig=$1
thumb=$2
dest=$3

arrow_head="l -15,-5  +5,+5  -5,+5  +15,-5 z"

convert -size 100x30 xc: -draw 'stroke skyblue fill skyblue rectangle 30,14 70,16' \
        -draw "stroke skyblue fill skyblue path 'M 70,15  $arrow_head' " \
	arrow_horizontal.png

# eom arrow_horizontal.png

convert ${orig} -resize 400x400 arrow_horizontal.png ${thumb} -gravity Center +append -resize 70% -bordercolor White -border 10x10 ${dest}

eom ${dest}


#!/bin/bash
# Azure HPC Diagnostics Tool
# Gathers Diagnostic info from guest VM
#
# tarball directory structure:
# - VM Information
#   - dmesg.log
#   - waagent.log
#   - lspci.txt
#   - lsvmbus.log
#   - ifconfig.txt
#   - sysctl.txt
#   - uname.txt
#   - dmidecode.txt
#   - journald.log|syslog|messages
#   - services
#   - selinux
#   - hyperv/kvp_pool*.txt
# - CPU
#   - lscpu.txt
# - Memory
#   - stream.txt
#   - ulimit
#   - zone_reclaim_mode
# - Infiniband
#   - ib-vmext-status
#   - ibstat.out
#   - ibstatus.out
#   - ibv_devinfo.out
#   - pkeys
#   - ethtool.out (ENDURE)
#   - rate (ENDURE)
#   - state (ENDURE)
#   - phys_state (ENDURE)
# - Nvidia GPU
#   - nvidia-bug-report.log.gz
#   - nvidia-installer.log
#   - nvidia-vmext-status
#   - nvidia-smi.out
#   - nvidia-smi-q.out
#   - nvidia-smi-nvlink.out
#   - nvidia-debugdump.zip (only Nvidia can read)
#   - dcgm-diag-2.log
#   - dcgm-diag-3.log
#   - nvvs.log
#   - stats_*.json
#
# Outputs:
# - transcript of run
# - name of tarball to stdout
# - tarball of all logs
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

####################################################################################################
# Begin Constants
####################################################################################################

STREAM_URL='https://azhpcstor.blob.core.windows.net/diagtool-binaries/stream.tgz'
LSVMBUS_URL='https://raw.githubusercontent.com/torvalds/linux/master/tools/hv/lsvmbus'
HPC_DIAG_URL='https://raw.githubusercontent.com/Azure/azhpc-diagnostics/main/Linux/src/gather_azhpc_vm_diagnostics.sh'
SCRIPT_DIR="$( cd "$( dirname "$0" )" >/dev/null 2>&1 && pwd )"
SYSFS_PATH=/sys # store as a variable so it is mockable
ETC_PATH=/etc
PROC_PATH=/proc
VAR_PATH=/var

NVIDIA_PCI_ID=10de
GPU_PCI_CLASS_ID=0302

# Mapping for stream benchmark(AMD only)
declare -A CPU_LIST
CPU_LIST=(["Standard_HB120rs_v2"]="0 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117"
          ["Standard_HB60rs"]="0 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57")
RELEASE_DATE=20220328 # update upon each release
COMMIT_HASH=$(
    (
        command -v git >/dev/null &&
        cd "$SCRIPT_DIR" &&
        git config --get remote.origin.url | grep -q 'Azure/azhpc-diagnostics.git$' &&
        git rev-parse HEAD 2>/dev/null
    ) ||
    echo 'Unknown')
VERSION_INFO="$RELEASE_DATE-$COMMIT_HASH"

HELP_MESSAGE="
Usage: $0 [OPTION]
Gather diagnostic info for the current Azure HPC VM.
Has multiple run levels
Exports data into a tarball in the script directory.

Output control:
 -d, --dir=DIR         specify custom output location

Miscellaneous:
 -V, --version         display version information and exit
 -h, --help            display this help text and exit

Execution Mode:
 --gpu-level=GPU_LEVEL dcgmi run level (default is 1)
 --mem-level=MEM_LEVEL set to 1 to run stream test (default is 0)
 --no-update           do not prompt for auto-update
 --offline             skips steps that require Internet access

For more information on this script and the data it gathers, visit its Github:

https://github.com/Azure/azhpc-diagnostics
"

####################################################################################################
# End Constants
####################################################################################################

####################################################################################################
# Begin Utility Functions
####################################################################################################

print_log() {
    echo "$@"
    echo "$@" >> "$DIAG_DIR/transcript.log"
}

validate_run_level() {
    # test if arg is integer
    if ! test "$1" -eq "$1" 2>/dev/null; then
        failwith "Invalid run level: $1. Should be integer."
    fi
}

validate_out_dir() {
    mkdir -p "$1" ||
    failwith "Invalid output directory: $1."
}

failwith() {
    echo "$@" 'Exiting'
    exit 1
}

get_python_command() {
    compgen -c | grep -m 1 '^python[23]$'
}

prompt() {
    local message="$1"
    local response
    local counter=2
    while (( counter-- > 0 )); do
        read -r -p "$message [y/N]" response
        case "$response" in
            [yY][eE][sS]|[yY]) return 0;;
            [nN][oO]|[nN]) return 1;;
        esac
    done
    return 1
}

read_binary_record() {
    od --skip-bytes="$1" --read-bytes="$2" --format=c --width=1 |
    awk '{
        if ($2 != "\\0") {
            printf("%s",$2)
        } else {
            printf("\n"); exit
        }
    }
    END {
        printf("\n")
        }'
}

is_infiniband_sku() {
    echo "$1" | cut -d_ -f2 | grep -q r
}

is_endure_sku() {
    echo "$1" | grep -Eiq '^Standard_(H16m?r|NC24rs?)$'
}

is_nvidia_sku() {
    local clean
    clean=$(echo "$1" | sed s/_Promo//g | tr '[:upper:]' '[:lower:]')

    [[ "$clean" =~ ^standard_nc(6|12|24r?)$ ]] ||
    [[ "$clean" =~ ^standard_nc(6|12|24r?)s_v2$ ]] ||
    [[ "$clean" =~ ^standard_nc(6|12|24r?)s_v3$ ]] ||
    \
    [[ "$clean" =~ ^standard_nc(4|8|16|64)as_t4_v3$ ]] ||
    \
    [[ "$clean" =~ ^standard_nd(6|12|24r?)s$ ]] ||
    [[ "$clean" =~ ^standard_nd40r?s_v2$ ]] ||
    [[ "$clean" =~ ^standard_nd96am?sr(_a100)?_v4$ ]] ||
    \
    [[ "$clean" =~ ^standard_nv(6|12|24)$ ]] ||
    [[ "$clean" =~ ^standard_nv(6|12|24)s_v2$ ]] ||
    [[ "$clean" =~ ^standard_nv(12|24|48)s_v3$ ]]
}

is_gpu_compute_sku() {
    echo "$1" | cut -d_ -f1 --complement | grep -Eiq '^N(C|D)'
}

is_vis_sku() {
    echo "$1" | cut -d_ -f1 --complement | grep -Eiq '^NV'
}

is_amd_gpu_sku() {
    local clean
    clean=$(echo "$1" | sed s/_Promo//g | tr '[:upper:]' '[:lower:]')

    [[ "$clean" =~ ^standard_nv(4|8|16|32)as_v4$ ]]
}

get_cpu_list() {
    echo "${CPU_LIST[$1]}"
}

if tput cols >/dev/null 2>/dev/null && (( $(tput cols) < 80 )); then
    COLUMNS=$(tput cols)
else
    COLUMNS=80
fi

print_enclosed() {
    local line
    while (( "$#" )); do
        line='#'
        while
            line="$line $1"
            shift
            (( "$#" && ${#line} + 1 + ${#1} <  "$COLUMNS" - 2 ))
        do true; done
        while (( ${#line} < "$COLUMNS" - 2 )); do
            line="$line "
        done
        echo "$line #"
    done
}

print_divider() {
    for _ in $(seq "$COLUMNS"); do echo -n '#'; done
    echo ''
}

check_for_updates() {
    local message="You are not running the latest release of this tool. Switch to latest version?"

    local tmpfile
    tmpfile=$(mktemp)
    curl -s "$HPC_DIAG_URL" >"$tmpfile" || return 1
    if ! cmp --silent "$0" "$tmpfile"; then
        if prompt "$message"; then
            mv "$tmpfile" "$0"
            bash "$0" "$RUNTIME_OPTIONS"
            exit $?
        else
            return 0
        fi
    fi
    rm "$tmpfile"
}

get_metadata() {
    local path="$1"
    curl -s -H Metadata:true "http://169.254.169.254/metadata/instance/$path?api-version=2021-03-01&format=text"
}

####################################################################################################
# End Utility Functions
####################################################################################################

####################################################################################################
# Begin Helper Functions
####################################################################################################

validate_options() {
    if [ "$OFFLINE" = true ] && [ "$MEM_LEVEL" -gt 0 ]; then
        echo 'Cannot run stream test in offline mode.'
        return 1
    else
        return 0
    fi
}

run_lsvmbus_resilient() {
    local LSVMBUS_PATH
    local PYTHON

    if command -v lsvmbus >/dev/null; then
        print_log -e "\tWriting Hyper-V VMBus device list to {output}/VM/lsvmbus.log"
        mkdir -p "$DIAG_DIR/VM"
        lsvmbus -vv >"$DIAG_DIR/VM/lsvmbus.log"
    else
        if ! PYTHON="$(get_python_command)"; then
            print_log -e '\tNeither lsvmbus nor python detected; skipping'
            return 1
        elif [ "$OFFLINE" = true ]; then
            print_log -e '\tlsvmbus not installed and offline mode enabled; skipping'
            return 1
        else
            print_log -e "\tNo lsvmbus installed; pulling a copy from Github"
            LSVMBUS_PATH=$(mktemp)
            if curl -s "$LSVMBUS_URL" > "$LSVMBUS_PATH"; then
                print_log -e "\tWriting Hyper-V VMBus device list to {output}/VM/lsvmbus.log"
                mkdir -p "$DIAG_DIR/VM"
                $PYTHON "$LSVMBUS_PATH" -vv >"$DIAG_DIR/VM/lsvmbus.log"
                rm -f "$LSVMBUS_PATH"
            else
                print_log -e '\tFailed to download lsvmbus; skipping'
            fi
        fi
    fi
}

filter_syslog() {
    # To avoid overcollecting, filter out messages like this
    # Dec 31 23:59:59 hostname audit: CWD cwd="/"
    awk '!index($5,"audit")'
}

fetch_syslog() {
    if systemctl is-active systemd-journald >/dev/null 2>/dev/null && command -v journalctl >/dev/null; then
        print_log -e "\tDumping system logs from journald to {output}/VM/journald.log"
        journalctl | filter_syslog > "$DIAG_DIR/VM/journald.log"
    elif [ -f /var/log/syslog ]; then
        print_log -e "\tCopying sytem logs from /var/log/syslog to {output}/VM/syslog"
        filter_syslog </var/log/syslog >"$DIAG_DIR/VM/syslog"
    elif [ -f /var/log/messages ]; then
        print_log -e "\tCopying sytem logs from /var/log/messages to {output}/VM/messages"
        filter_syslog </var/log/messages >"$DIAG_DIR/VM/messages"
    else
        print_log -e "\tNo system logs found. Checked journald and /var/log/syslog|messages"
    fi
}

read_kvp() {
    local filename="$1"
    local KEY_BYTELEN=512
    local VALUE_BYTELEN=2048
    local RECORD_BYTELEN=$(( KEY_BYTELEN + VALUE_BYTELEN ))
    local file_len
    file_len=$(wc --bytes "$filename" | cut -d' ' -f1)
    local record_count=$(( file_len / RECORD_BYTELEN ))
    local key value
    for i in $(seq 0 $(( record_count - 1 ))); do
        key=$(read_binary_record $(( RECORD_BYTELEN * i )) $KEY_BYTELEN <"$filename")
        value=$(read_binary_record $(( RECORD_BYTELEN * i + KEY_BYTELEN )) $VALUE_BYTELEN <"$filename")
        printf "Key: %s; Value: %s\n" "$key" "$value"
    done
}

run_vm_diags() {
    mkdir -p "$DIAG_DIR/VM"

    if [ -f /var/log/waagent.log ]; then
        print_log -e "\tCopying Azure VM Agent logs to {output}/VM/waagent.log"
        cp /var/log/waagent.log "$DIAG_DIR/VM/waagent.log"
    else
        print_log -e "\tCould not locate Azure VM Agent logs at /var/log/waagent.log"
    fi

    print_log -e "\tWriting PCI Device List to {output}/VM/lspci.txt"
    lspci -vv >"$DIAG_DIR/VM/lspci.txt"

    run_lsvmbus_resilient

    print_log -e "\tWriting network interface list to {output}/VM/ifconfig.txt"
    ip -stats -human-readable address >"$DIAG_DIR/VM/ifconfig.txt"

    print_log -e "\tWriting kernel parameters to {output}/VM/sysctl.txt"
    sysctl --all --ignore 2>/dev/null >"$DIAG_DIR/VM/sysctl.txt"

    print_log -e "\tWriting system information to {output}/VM/uname.txt"
    uname -a >"$DIAG_DIR/VM/uname.txt"

    print_log -e "\tDumping System Management BIOS table to {output}/VM/dmidecode.txt"
    dmidecode >"$DIAG_DIR/VM/dmidecode.txt"

    print_log -e "\tWriting kernel message buffer to {output}/VM/dmesg.log"
    dmesg -T >"$DIAG_DIR/VM/dmesg.log"

    print_log -e "\tWriting list of active kernel modules to {output}/VM/lsmod.txt"
    lsmod >"$DIAG_DIR/VM/lsmod.txt"

    fetch_syslog

    mkdir -p "$DIAG_DIR/VM/hyperv"
    for file in "$VAR_PATH"/lib/hyperv/.kvp_pool*; do
        local filename
        filename=$(basename "$file" | sed 's/^\.//g')
        print_log -e "\tDumping Hyper-V KVP data from $file to {output}/VM/kvp/$filename.txt"
        read_kvp "$file" >"$DIAG_DIR/VM/hyperv/$filename.txt"
    done

    local services=(iptables firewalld cpupower waagent walinuxagent)
    if systemctl >/dev/null; then
        for service in "${services[@]}"; do
            print_log -e "\tWriting status of service $service {output}/VM/services"
            echo "$service $(systemctl is-active "$service")" >> "$DIAG_DIR/VM/services"
        done
    fi

    if [ -f $ETC_PATH/sysconfig/selinux ]; then
        print_log -e "\tWriting status of selinux {output}/VM/selinux"
        grep -V '^[[:space]]#' $ETC_PATH/sysconfig/selinux |
        grep 'SELINUX=\(enforcing\|permissive\|disabled\)' $ETC_PATH/sysconfig/selinux |
        head -1 >"$DIAG_DIR/VM/selinux"
        [ -s "$DIAG_DIR/VM/selinux" ] || rm "$DIAG_DIR/VM/selinux"
    fi
}

run_cpu_diags() {
    mkdir -p "$DIAG_DIR/CPU"

    print_log -e "\tWriting CPU architecture details to {output}/CPU/lscpu.txt"
    lscpu >"$DIAG_DIR/CPU/lscpu.txt"
}

run_stream() {
    local STREAM_PATH="$DIAG_DIR/Memory/stream.tgz"
    local cpu_list
    cpu_list=$(get_cpu_list "$VM_SIZE")
    if [ -z "$cpu_list" ]; then
        print_log -e "\tCurrent VM Size is not supported for stream tests. Skipping"
        return 1
    fi

    # Download precompiled stream library
    print_log -e "\tDownloading precompiled Stream binary from Azure HPC Storage"
    if curl -s "$STREAM_URL" > "$STREAM_PATH"; then
        tar xzf "$STREAM_PATH" -C "$DIAG_DIR/Memory/"

        # run stream tests
        local stream_bin="$DIAG_DIR/Memory/Stream/stream_zen_double"
        if [ -f "$stream_bin" ]; then
            print_log -e "\tRunning Stream Benchmark and writing results to {output}/Memory/stream.txt"
            "$stream_bin" 400000000 "$cpu_list" > "$DIAG_DIR/Memory/stream.txt"
        else
            print_log -e "\tFailed to unpack stream binary to $stream_bin; unable to run stream memory tests."
        fi

        # Clean up
        rm -r "$DIAG_DIR/Memory/Stream"
        rm "$DIAG_DIR/Memory/._Stream"
        rm "$DIAG_DIR/Memory/stream.tgz"
    else
        print_log -e "\tUnable to download stream memory benchmark"
    fi
}

run_memory_diags() {
    mkdir -p "$DIAG_DIR/Memory"
    cp $ETC_PATH/security/limits.conf "$DIAG_DIR/Memory"
    cp $PROC_PATH/sys/vm/zone_reclaim_mode "$DIAG_DIR/Memory"
    if [ "$MEM_LEVEL" -gt 0 ]; then
        print_log ''
        print_log "Running Memory Performance Test"
        run_stream
    fi
}

run_infiniband_diags() {
    if [ -f /var/log/azure/ib-vmext-status ]; then
        mkdir -p "$DIAG_DIR/Infiniband"
        print_log -e "\tCopying Infiniband Driver Extension logs to {output}/Infiniband/ib-vmext-status"
        cp /var/log/azure/ib-vmext-status "$DIAG_DIR/Infiniband"
    fi

    local ib_interfaces
    if command -v ibstatus >/dev/null; then
        mkdir -p "$DIAG_DIR/Infiniband"

        print_log -e "\tQuerying Infiniband device status, writing to {output}/Infiniband/ibstatus.out"
        ibstatus > "$DIAG_DIR/Infiniband/ibstatus.out"

        ib_interfaces=$(
            awk '
            /Infiniband device/ { device_name=$3 }
            /link_layer:\s+InfiniBand/ { print device_name }' "$DIAG_DIR/Infiniband/ibstatus.out" | tr -d "'"
        )
        if command -v ibstat >/dev/null; then
            print_log -e "\tWriting ibstat info for device(s) $(echo "$ib_interfaces" | xargs) to {output}/Infiniband/ibstat.out"
            for ib_interface in $ib_interfaces; do
                ibstat "$ib_interface"
            done >"$DIAG_DIR/Infiniband/ibstat.out"
        else
            print_log -e "\tibstat not found."
        fi

        print_log -e "\tWriting Infiniband device info to {output}/Infiniband/ibv_devinfo.out"
        ibv_devinfo -v > "$DIAG_DIR/Infiniband/ibv_devinfo.out" 2>&1
    elif is_endure_sku "$VM_SIZE"; then
        print_log -e "\tNon-SR-IOV VM size detected."
        local device_paths=("$SYSFS_PATH"/class/infiniband/*/ports/1)
        if ip address show eth1 >/dev/null && [ ${#device_paths[@]} -eq 1 ] && [ -d "${device_paths[0]}" ]; then
            local device_path=${device_paths[0]}
            mkdir -p "$DIAG_DIR/Infiniband"
            print_log -e "\tCopying $device_path/state to {output}/Infiniband/state"
            cp "$device_path/state" "$DIAG_DIR/Infiniband"
            print_log -e "\tCopying $device_path/rate to {output}/Infiniband/rate"
            cp "$device_path/rate" "$DIAG_DIR/Infiniband"
            print_log -e "\tCopying $device_path/phys_state to {output}/Infiniband/phys_state"
            cp "$device_path/phys_state" "$DIAG_DIR/Infiniband"
            ethtool eth1 >"$DIAG_DIR/Infiniband/ethtool.out"
        else
            print_log "ENDURE : No IB devices found"
        fi
        ib_interfaces=$(basename "$SYSFS_PATH"/class/infiniband/*)
    else
        print_log -e "\tNo Infiniband Driver Detected"
    fi

    print_log -e "\tChecking for Infiniband pkeys"
    for device in $ib_interfaces; do
        local dir="$SYSFS_PATH/class/infiniband/$device"
        if ! [ -d "$dir" ]; then
            print_log "\tDevice $device not showing up in $SYSFS_PATH/class/infiniband/"
        else
            print_log -e "\tChecking for Infiniband pkeys in $dir"
        fi
        mkdir -p "$DIAG_DIR/Infiniband/$device/pkeys"

        local pkey_count
        local pkey_dir="$SYSFS_PATH/class/infiniband/$device/ports/1/pkeys"
        pkey_count=$(find "$pkey_dir/" -maxdepth 1 -name '[0-9]*' | wc -l)
        if [ "$pkey_count" -gt 0 ]; then
            mkdir -p "$(realpath "$DIAG_DIR")/Infiniband/$device/pkeys"
            print_log -e "\tFound $pkey_count pkeys in $pkey_dir; copying them to {output}/Infiniband/$device/pkeys/"
            cp "$SYSFS_PATH/class/infiniband/$device/ports/1/pkeys/"* "$(realpath "$DIAG_DIR")/Infiniband/$device/pkeys"
        else
            print_log -e "\tFound no pkeys in $dir"
        fi
    done
}

is_dcgm_installed() {
    command -v nv-hostengine >/dev/null && command -v dcgmi >/dev/null
}

reset_gpu_state() {
    for id in $gpus_wout_persistence; do
        print_log -e "\tDisabling Persistence Mode for GPU $id"
        nvidia-smi -i "$id" -pm 0 >/dev/null
    done
    if [ "$nv_hostengine_already_running" = false ]; then
        print_log -e "\tTerminating nv-hostengine"
        nv-hostengine --term >/dev/null
    fi
}

run_dcgm() {
    # because dcgmi makes files in working dir
    pushd "$DIAG_DIR/Nvidia" >/dev/null || return 1

    # start hostengine, remember if it was already running
    local discovery_output
    discovery_output=$(dcgmi discovery -l)
    if [ "$?" -eq 255 ] || echo "$discovery_output" | grep -iq 'Unable to connect to host engine'; then
        nv_hostengine_already_running=true
    else
        nv_hostengine_already_running=false
    fi

    if [ "$nv_hostengine_already_running" = false ]; then
        print_log -e "\tTemporarily starting nv-hostengine"
        nv-hostengine >/dev/null
    fi

    # enable_persistence_mode for all gpus
    gpus_wout_persistence=$(dcgmi diag -r 1 |
        grep -A1 'Persistence Mode.*Fail' |
        grep -o 'GPU [[:digit:]]\+' |
        awk '{print $2}'
    )
    for id in $gpus_wout_persistence; do
        print_log -e "\tTemporarily enabling Persistence Mode for GPU $id"
        nvidia-smi -i "$id" -pm 1 >/dev/null
    done

    case "$GPU_LEVEL" in
    1)
        print_log -e "\tRunning DCGM diagnostics Level 1 (~ < 1 min)"
        timeout 1m dcgmi diag -r 1 >dcgm-diag.log
        ;;
    2)
        print_log -e "\tRunning DCGM diagnostics Level 2 (~ 2 min)"
        timeout 5m dcgmi diag -r 2 >dcgm-diag.log
        ;;
    3)
        print_log -e "\tRunning DCGM diagnostics Level 3 (~ 12 min)"
        timeout 20m dcgmi diag -r 3 >dcgm-diag.log
        ;;
    *)
        print_log -e "\tInvalid run-level for dcgm: $GPU_LEVEL"
        ;;
    esac
    if [ $? -eq 124 ]; then
        print_log -e "\tDCGM timed out"
    fi

    # reset state to before script ran
    reset_gpu_state

    popd >/dev/null || failwith "Failed to popd back to working directory"
}

is_nvidia_driver_installed() (
    lsmod | awk '{print $1}' | grep -Eiq '^nvidia$'
)

investigate_nvidia_driver_installation() (
    if [ -f /var/log/nvidia-installer.log ]; then
        mkdir -p "$DIAG_DIR/Nvidia"
        print_log -e "\tCopying Nvidia GPU Driver Installer logs to {output}/Nvidia/nvidia-installer.log"
        cp /var/log/nvidia-installer.log "$DIAG_DIR/Nvidia"
    else
        print_log -e "\tNo Nvidia GPU Driver Installer logs found."
    fi
)

run_nvidia_diags() {

    if [ -f /var/log/azure/nvidia-vmext-status ]; then
        mkdir -p "$DIAG_DIR/Nvidia"
        print_log -e "\tCopying Nvidia GPU Driver Extension logs to {output}/Nvidia/nvidia-vmext-status"
        cp /var/log/azure/nvidia-vmext-status "$DIAG_DIR/Nvidia"
    fi

    if ! is_nvidia_driver_installed; then
        print_log -e "No NVIDIA driver found. Checking for installation logs"
        investigate_nvidia_driver_installation
    elif ! command -v nvidia-smi >/dev/null; then
        print_log -e "NVIDIA driver is installed, but can't find nvidia-smi. Please check that it's on the PATH."
    else
        mkdir -p "$DIAG_DIR/Nvidia"
        print_log -e "\tQuerying Nvidia GPU Info, writing to {output}/Nvidia/nvidia-smi-q.out"
        timeout 5m nvidia-smi -q >"$DIAG_DIR/Nvidia/nvidia-smi-q.out"
        if [ $? -eq 124 ]; then
            print_log -e "\tnvidia-smi -q timed out"
        else
            print_log -e "\tRunning plain nvidia-smi, writing to {output}/Nvidia/nvidia-smi.out"
            timeout 5m nvidia-smi >"$DIAG_DIR/Nvidia/nvidia-smi.out"
        fi
        print_log -e "\tDumping Nvidia GPU internal state to {output}/Nvidia/nvidia-debugdump.zip"
        nvidia-debugdump --dumpall --file "$DIAG_DIR/Nvidia/nvidia-debugdump.zip"
        if is_dcgm_installed; then
            run_dcgm
        fi
        print_log -e "\tChecking nvlinks"
        nvidia-smi nvlink -s >"$DIAG_DIR/Nvidia/nvlink.out"
    fi

    if command -v nvidia-bug-report.sh >/dev/null; then
        mkdir -p "$DIAG_DIR/Nvidia"
        print_log -e "\tRunning nvidia-bug-report.sh and outputting to {output}/Nvidia/nvidia-bug-report.log.gz"
        print_log -e "\tIn the event of hardware failure, this log may be shared with Nvidia:"
        print_log -e "$(timeout 5m nvidia-bug-report.sh --safe-mode --extra-system-data --output-file "$DIAG_DIR/Nvidia/nvidia-bug-report.log" | sed 's/^/\t/')"
    fi
}

is_extension_running() {
    sudo ps aux | grep -v grep | grep -m1 'nvidia-vmext.sh enable'
}

run_amd_gpu_diags() {
    print_log -e "\tNo AMD GPU diagnostics supported at this time."
}

function report_bad_gpu {
    if ! PARSED_OPTIONS=$(getopt -n "$0" -o "i" --long "index:,reason:,pci-domain:"  -- "$@"); then
        echo "Illegal arguments"
        return 1
    fi

    eval set -- "$PARSED_OPTIONS"
    local index reason pci_domain
    while [ "$1" != "--" ]; do
        case "$1" in
            -i|--index) index=$2;;
            --reason) reason=$2;;
            --pci-domain) pci_domain=$2;;
        esac
        shift 2
    done
    shift

    if [ -n "$index" ] && [ -n "$pci_domain" ]; then
        if [ "$pci_domain" != "$(nvidia-smi --query-gpu=pci.domain -i "$index" --format=csv,noheader)" ]; then
            print_log -e "\tmismatched gpu index and pci domain passed in"
            return 1
        fi
    elif [ -n "$index" ]; then
        pci_domain=$(nvidia-smi --query-gpu=pci.domain -i "$index" --format=csv,noheader) || {
            print_log -e "nvidia-smi failed during bad gpu reporting"
            return 1
        }
    elif [ -n "$pci_domain" ]; then
        index=$(nvidia-smi --query-gpu=pci.domain,index --format=csv,noheader 2>/dev/null | grep -i "^0x$pci_domain" | cut -d' ' -f 2)
    fi

    local serial
    [ -n "$index" ] &&
        serial=$(nvidia-smi --query-gpu=serial -i "$index" --format=csv,noheader) ||
        serial=UNKNOWN

    local device
    local DEVICES_PATH="$SYSFS_PATH/bus/vmbus/devices"
    device=$(find -L "$DEVICES_PATH" -maxdepth 2 -mindepth 2 -iname "*${pci_domain#0x}*")
    local bus_id
    bus_id=$(basename "$(dirname "$device")")
    print_log -e "\tBAD GPU ($reason) with bus Id $bus_id and serial number $serial"
}

function check_page_retirement {
    local remapped_rows sbe_dbe pci_domain
    remapped_rows=$(nvidia-smi --query-remapped-rows=remapped_rows.failure,gpu_bus_id --format=csv,noheader) || {
        print_log -e "\tcheck_page_retirement called, but nvidia-smi is failing"
        return 1
    }
    sbe_dbe=$(nvidia-smi --query-gpu=retired_pages.sbe,retired_pages.dbe, --format=csv,noheader) || {
        print_log -e "\tcheck_page_retirement called, but nvidia-smi is failing"
        return 1
    }
    if echo "$remapped_rows" | grep -Eiq '\[N/A\]'; then
        print_log -e "\tChecking for GPUs over the page retirement threshold"
        local i=0
        echo "$sbe_dbe" | sed 's/, /\t/g' |
        while read -r sbe dbe; do
            local retired_page_count=$(( sbe + dbe ))
            if (( retired_page_count >= 60 )); then
                report_bad_gpu --index="$i" --reason="DBE($retired_page_count)"
            fi
            ((i++))
        done
    else
        print_log -e "\tChecking for GPUs with row remapping failures"
        echo "$remapped_rows" | sed 's/, /\t/g' |
        while read -r row_remap_failure pci_bus_id; do
            if (( row_remap_failure == 1 )); then
                pci_domain=$(echo "$pci_bus_id" | cut -d: -f1 | sed -E 's/^.{4}//g')
                report_bad_gpu --pci-domain="$pci_domain" --reason="Row Remap Failure"
            fi
        done
    fi
}

function check_inforom {
    # e.g. WARNING: infoROM is corrupted at gpu 15B5:00:00.0
    local keywords='WARNING: infoROM is corrupted at gpu'
    local nvsmi_domains
    nvsmi_domains=$(nvidia-smi --query-gpu=pci.domain --format=csv,noheader) || {
        print_log -e "\tcheck_inforom called, but nvidia-smi is failing"
        return 1
    }
    print_log -e "\tChecking for GPUs with corrupted infoROM"

    grep "$keywords" "$DIAG_DIR/Nvidia/nvidia-smi.out" | while IFS= read -r warning; do
        local pci_domain
        pci_domain=$(echo "$warning" | awk '{print $NF}' | awk -F: '{print $1}')
        local i
        i=$(echo "$nvsmi_domains" | awk "/$pci_domain/{print FNR}")
        ((i--)) # convert to 0-index
        report_bad_gpu --index="$i" --reason="infoROM Corrupted"
    done
}

function check_missing_gpus {
    local pci_domains nvsmi_domains
    nvsmi_domains=$(mktemp)
    nvidia-smi --query-gpu=pci.domain --format=csv,noheader >"$nvsmi_domains" || {
        print_log -e "\tcheck_missing_gpus called, but nvidia-smi is failing"
        return 1
    }
    pci_domains=$(lspci -d "$NVIDIA_PCI_ID:" -mnD | grep -E "\S+\s\"$GPU_PCI_CLASS_ID\"" | cut -d: -f1)
    print_log -e "\tChecking for GPUs that don't appear in nvidia-smi"
    for pci_domain in $pci_domains; do
        if ! grep -iq "^0x$pci_domain$" "$nvsmi_domains"; then
            report_bad_gpu --pci-domain="$pci_domain" --reason="GPU not coming up in nvidia-smi"
        fi
    done
    rm "$nvsmi_domains"
}

function check_nvlinks {
    awk '/GPU/{i=$2} /inactive/{print i}' "$DIAG_DIR/Nvidia/nvidia-smi-nvlink.out" | tr -d : | uniq |
    while read -r bad_gpu; do
        report_bad_gpu --index $bad_gpu --reason "NVLINK(s) inactive"
    done
}

function check_nouveau {
    if grep -q nouveau "$DIAG_DIR/VM/lsmod.txt"; then
        print_log -e '\tNouveau driver detected. This driver is unsupported.'
    fi
}

function check_pci_bandwidth {
    print_log -e "\tChecking PCIe speed training for GPUs"

    for pci_id in $(lspci -d "$NVIDIA_PCI_ID:" -mnD | awk '$2 == "\"'"$GPU_PCI_CLASS_ID"'\"" {print $1}'); do
        local speed_cap width_cap speed_sta width_sta
        speed_cap=$(lspci -vv -s "$pci_id" | grep 'LnkCap:' | grep -o 'Speed [0-9.]\+GT/s' | grep -o '[0-9.]\+')
        speed_sta=$(lspci -vv -s "$pci_id" | grep 'LnkSta:' | grep -o 'Speed [0-9.]\+GT/s' | grep -o '[0-9.]\+')
        width_cap=$(lspci -vv -s "$pci_id" | grep 'LnkCap:' | grep -o 'Width x[0-9]\+' | grep -o '[0-9]\+')
        width_sta=$(lspci -vv -s "$pci_id" | grep 'LnkSta:' | grep -o 'Width x[0-9]\+' | grep -o '[0-9]\+')
        if [ "$speed_sta" -ne "$speed_cap" ] || [ "$width_sta" -ne "$width_cap" ]; then
            local reason="PCIe link not showing expected performance: OBSERVED Speed ${speed_sta}GT/s, Width x${width_sta}; EXPECTED ${speed_cap}GT/s, Width x${width_cap}"
            report_bad_gpu --pci-domain="$(echo "$pci_id" | cut -d: -f1)" --reason="$reason"
        fi
    done
}

function check_pkeys {
    local device
    for device_path in "$DIAG_DIR"/Infiniband/*; do
        [ -d "$device_path" ] || continue
        device=$(basename "$device_path")
        for pkeyNum in {0..1}; do
            if ! [ -s "$DIAG_DIR/Infiniband/$device/pkeys/$pkeyNum" ]; then
                print_log -e "\tCould not find pkey $pkeyNum for device $device"
            fi
        done
    done
}

function check_tuning() {
    print_log -e "\tChecking VM configuration against recommended settings."
    if [ "$(cat "$DIAG_DIR/Memory/zone_reclaim_mode")" -ne 1 ]; then
        print_log 'Set zone_reclaim_mode to 1'
    fi

    awk '/^\*/{
        switch ($3) {
            case "memlock":
                desired="unlimited"
                break
            case "nofile":
                desired=65535
                break
            case "stack":
                desired="unlimited"
            default:
                next
        }
        if ($4 != desired) {
            printf("Consider setting ulimit %s to %s\n", $3, desired)
        }
    }' "$DIAG_DIR/Memory/limits.conf" | sort | uniq | while read -r warning; do
        print_log -e "\t$warning"
    done

    if [ -s "$DIAG_DIR/VM/selinux" ] && [ "$(cut -d= -f2 "$DIAG_DIR/VM/selinux")" = 'enforcing' ]; then
        print_log -e "\tConsider disabling selinux to avoid interfering with MPI"
    fi
}

####################################################################################################
# End Helper Functions
####################################################################################################

####################################################################################################
# Begin Traps
####################################################################################################

function ctrl_c() {
        echo "** Aborting Diagnostics"
        echo "** Resetting system state"
        reset_gpu_state
        echo "** Done!"

        exit
}
trap ctrl_c INT

####################################################################################################
# End Traps
####################################################################################################

function main {
    print_divider
    print_enclosed Azure HPC Diagnostics Tool
    print_divider
    print_enclosed "NOTICES:"
    print_divider
    print_enclosed This tool generates and bundles together various logs and diagnostic information. It, however, DOES NOT TRANSMIT any of said data. It is left to the user to choose to transmit this data to Microsoft.
    print_divider
    print_enclosed Some of this info, such as IP addresses, may be Personally Identifiable Information. It is up to the user to redact any sensitive info from the output 'if' necessary before sending it to Microsoft.
    print_divider
    print_enclosed This tool invokes various 3rd party tools 'if' they are present on the system Please review them and their EULAs at:
    print_enclosed "https://github.com/Azure/azhpc-diagnostics"
    print_divider
    print_enclosed WARNING: THINK BEFORE YOU RUN THIS
    print_divider
    print_enclosed This tool runs benchmarks against system resource such as Memory and GPU. Expect it to DEGRADE PERFORMANCE 'for' or otherwise INTERFERE WITH any other processes running on this system that use such resources. It is advised that you DO NOT RUN THIS TOOL ALONGSIDE ANY OTHER JOBS on the system.
    print_divider
    print_enclosed Interrupt this tool at any 'time' to force it to reset system state and terminate.
    print_divider
    if ! prompt "Please confirm that you understand"; then
        echo "No confirmation received"
        echo "Exiting"
        exit
    fi

    VM_SIZE=$(get_metadata compute/vmSize)
    VM_ID=$(get_metadata compute/vmId)

    IMAGE_PUBLISHER=$(get_metadata compute/storageProfile/imageReference/publisher)
    IMAGE_OFFER=$(get_metadata compute/storageProfile/imageReference/offer)
    IMAGE_SKU=$(get_metadata compute/storageProfile/imageReference/sku)
    IMAGE_VERSION=$(get_metadata compute/storageProfile/imageReference/version)
    TIMESTAMP=$(date -u +"%F.UTC%H.%M.%S")

    echo ''

    DIAG_DIR="$DIAG_DIR_LOC/$VM_ID.$TIMESTAMP"

    rm -r "$DIAG_DIR" 2>/dev/null
    mkdir -p "$DIAG_DIR"

    # keep a trace of this execution
    exec 2> "$DIAG_DIR/hpcdiag.err"
    set -x

    print_log "Virtual Machine Details:"
    print_log -e "\tID: $VM_ID"
    print_log -e "\tSize: $VM_SIZE"
    if [ "$IMAGE_PUBLISHER" == 'Not found' ] ||
        [ "$IMAGE_OFFER" == 'Not found' ] ||
        [ "$IMAGE_SKU" == 'Not found' ] ||
        [ "$IMAGE_VERSION" == 'Not found' ]; then
        print_log -e "\tUnrecognized (Likely Custom) OS Image"
    else
        print_log -e "\tOS Image: $IMAGE_PUBLISHER:$IMAGE_OFFER:$IMAGE_SKU:$IMAGE_VERSION"
    fi
    print_log ''

    print_log 'Azure HPC Diagnostics Tool Run Details'
    print_log -e "\tTool Version: $VERSION_INFO"
    print_log -e "\tStart Time: $TIMESTAMP"
    print_log -e "\tRuntime Options:"
    for option in $RUNTIME_OPTIONS; do
        print_log -e "\t\t$option"
    done
    print_log -e "\tSelected Diagnostic Scenarios:"
    print_log -e "\t- General VM"
    print_log -e "\t- CPU"

    if [ "$MEM_LEVEL" -gt 0 ]; then
        print_log -e "\t- Stream Memory Benchmark"
    fi

    if is_infiniband_sku "$VM_SIZE"; then
        print_log -e "\t- Infiniband"
    fi

    if is_nvidia_sku "$VM_SIZE"; then
        print_log -e "\t- Nvidia GPU"
    fi

    if is_amd_gpu_sku "$VM_SIZE"; then
        print_log -e "\t- AMD GPU"
    fi
    print_log ''

    print_log "Collecting Linux VM Diagnostics"
    run_vm_diags

    print_log ''
    print_log "Collecting CPU Info"
    run_cpu_diags

    print_log ''
    print_log "Collecting Memory Info"
    run_memory_diags

    if is_infiniband_sku "$VM_SIZE"; then
        print_log ''
        print_log "Collecting Infiniband Info"
        run_infiniband_diags
    fi

    if is_nvidia_sku "$VM_SIZE"; then
        print_log ''
        print_log "Running Nvidia GPU Diagnostics"
        run_nvidia_diags
    fi

    if is_amd_gpu_sku "$VM_SIZE"; then
        print_log ''
        print_log "Collecting AMD GPU Info"
        run_amd_gpu_diags
    fi

    print_log ''
    print_log "End of Diagnostic Collection"
    print_log ''
    print_log "Checking for common issues"

    if is_nvidia_sku "$VM_SIZE" && [ -s "$DIAG_DIR/Nvidia/nvidia-smi.out" ]; then
        check_inforom
        check_page_retirement
        check_missing_gpus
        check_pci_bandwidth
        check_nvlinks
        if is_gpu_compute_sku "$VM_SIZE"; then
            check_nouveau
        fi
    fi

    if is_infiniband_sku "$VM_SIZE" && ! is_endure_sku "$VM_SIZE"; then
        check_pkeys
    fi

    if [ "$TUNING" = true ]; then
        print_log ''
        print_log 'Checking for opportunities for performance tuning'
        check_tuning
    fi

    print_log ''

    set +x

    print_divider
    print_enclosed 'Placing diagnostic files in the following location:'
    print_enclosed "$DIAG_DIR.tar.gz"
    print_divider
    print_enclosed If you have already opened a support request, you can take the tarball and follow this link to upload it:
    print_enclosed 'https://portal.azure.com/#blade/Microsoft_Azure_Support/HelpAndSupportBlade/managesupportrequest'
    print_divider
    tar czf "$DIAG_DIR.tar.gz" -C "$DIAG_DIR_LOC" "$VM_ID.$TIMESTAMP"  2>/dev/null && rm -r "$DIAG_DIR"
}

####################################################################################################
# Begin Option Parsing
####################################################################################################

GPU_LEVEL=1
MEM_LEVEL=0
DISPLAY_HELP=false
# should be /opt/azurehpc/diagnostics
DIAG_DIR_LOC="$SCRIPT_DIR"

# save options
RUNTIME_OPTIONS=$*

# Read in options
OPTIONS_LIST='dir:,help,gpu-level:,mem-level:,no-update,offline,tuning,version'
if ! PARSED_OPTIONS=$(getopt -n "$0"  -o d:hV --long "$OPTIONS_LIST"  -- "$@"); then
    echo "$HELP_MESSAGE"
    exit 1
fi
eval set -- "$PARSED_OPTIONS"

while [ "$1" != "--" ]; do
  case "$1" in
    -d|--dir)
        shift
        validate_out_dir "$1"
        DIAG_DIR_LOC=$(realpath "$1")
        ;;
    --gpu-level)
        shift
        validate_run_level "$1"
        GPU_LEVEL="$1"
        ;;
    -h|--help) DISPLAY_HELP=true;;
    --mem-level)
        shift
        validate_run_level "$1"
        MEM_LEVEL="$1"
        ;;
    --no-update) DISABLE_UPDATE=true;;
    --offline) OFFLINE=true;;
    --tuning) TUNING=true;;
    -V|--version) DISPLAY_VERSION=true;;
  esac
  shift
done
shift

if ! validate_options; then
    echo "Exiting due to invalid configuration"
    exit 1
fi

####################################################################################################
# End Option Parsing
####################################################################################################

if [ "$OFFLINE" != true ] && [ "$DISABLE_UPDATE" != true ] && ! [[ $- =~ 's' ]]; then
    check_for_updates
fi

if [ ! "${BASH_SOURCE[0]}" -ef "$0" ]; then
    # This lets us load all functions for unit testing.
    # We wouldn't want people sourcing this script anyway.
    echo "Script is being sourced. Skipping main execution."
elif [ "$DISPLAY_VERSION" = true ]; then
    echo "$VERSION_INFO"
elif [ "$DISPLAY_HELP" = true ]; then
    echo "$HELP_MESSAGE"
elif [ "$(whoami)" != 'root' ]; then
    failwith 'This script requires root privileges to run. Please run again with sudo'
elif ext_process=$(is_extension_running); then
    echo 'Detected a VM Extension installation script running in the background'
    echo 'Please wait for it to finish and retry'
    echo "Extension pid: $(echo "$ext_process" | awk '{print $2}')"
    exit 1
else
    main
fi


#!/bin/bash
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

SCRIPT_DIR="$( cd "$( dirname "$0" )" >/dev/null 2>&1 && pwd )"
PKG_ROOT="$(dirname "$SCRIPT_DIR")"
HPC_DIAG="$PKG_ROOT/src/gather_azhpc_vm_diagnostics.sh"

# BATS tests: this section should eventually absorb all tests
git submodule update --init # just in case, ensure BATS installation
"$SCRIPT_DIR/bats/bin/bats" "$SCRIPT_DIR" || exit 1

# these make sense as an associative array
# but hesitant to start using bash4 features
BASE_FILENAMES="
CPU/
CPU/lscpu.txt
VM/
VM/waagent.log
VM/dmesg.log
VM/lspci.txt
VM/lsvmbus.log
VM/ifconfig.txt
VM/sysctl.txt
VM/uname.txt
VM/dmidecode.txt
VM/lsmod.txt
VM/@(syslog|messages|journald.log)
transcript.log
hpcdiag.err"

NVIDIA_FILENAMES="Nvidia/nvidia-bug-report.log.gz
Nvidia/nvidia-smi-q.out
Nvidia/nvidia-smi.out
Nvidia/nvidia-debugdump.zip
Nvidia/nvlink.out"

NVIDIA_EXT_FILENAMES="Nvidia/nvidia-vmext-status"

NVIDIA_FOLDER="Nvidia/"

DCGM_FILENAMES="Nvidia/dcgm-diag.log"

MEMORY_FILENAMES="Memory/
Memory/stream.txt"

INFINIBAND_FILENAMES="Infiniband/ibstat.out
Infiniband/ibstatus.out
Infiniband/ibv_devinfo.out"

INFINIBAND_EXT_FILENAMES="Infiniband/ib-vmext-status"

INFINIBAND_FOLDER="Infiniband/"

# Test Functions

nosudo_basic_script_test(){
    local output
    if ! output=$(bash "$HPC_DIAG" --no-update "$1" | tee /dev/stderr); then
        echo 'FAIL 1'
        overall_retcode=1
    elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
        if [ "$(echo "$output" | wc -l)" -le 1 ]; then
            echo 'FAIL HELP'
            overall_retcode=1
            return 1
        else
            echo 'PASSED'
            return 0
        fi
    elif [ "$(echo "$output" | wc -l)" -ne 1 ]; then
        echo 'FAIL 2'
        overall_retcode=1
    else
        echo 'PASSED'
    fi
}

sudo_basic_script_test() {
    local script_args="$1"
    local additional_expected="$2"
    local additional_unexpected="$3"

    local retval=0

    local output
    output=$(yes | sudo bash "$HPC_DIAG" --no-update "$script_args") || retval=1
    echo "$output" 1>&2

    local tarball
    tarball=$(echo "$output" | grep -o '[^[:space:]]\+.tar.gz')
    if [ ! -s "$tarball" ]; then
        return 1
    fi

    local filenames
    filenames=$(tar xzvf "$tarball" | sed 's|^[^/]*/||g') || return 1

    local expected_patterns
    expected_patterns=$(cat <(echo "$BASE_FILENAMES") <(echo "$additional_expected") <(echo "$additional_unexpected") | sort | uniq -u)

    pushd "$(basename "$tarball" .tar.gz)" >/dev/null || return 1
    shopt -s extglob
    local expected_filenames
    for pattern in $expected_patterns; do
        if [ -e "$pattern" ]; then
            expected_filenames=$(printf '%s\n%s\n' "$expected_filenames" "$pattern")
        else
            retval=1
            echo "Could not find unique file for pattern $pattern"
        fi
    done
    shopt -u extglob
    popd >/dev/null || exit 1

    for filename in $filenames; do
        if [[ "$filename" =~ ^Nvidia/stats_.*$ ]] ||
           [[ "$filename" =~ ^Nvidia/nvvs.log$ ]] ||
           [[ "$filename" =~ ^Nvidia/nvidia-installer.log$ ]] ||
           [[ "$filename" =~ ^Infiniband/.* ]] ||
           [[ "$filename" =~ ^VM.* ]] ||
           [[ "$filename" =~ ^Memory/ ]] ||
           [[ "$filename" =~ ^Memory/zone_reclaim_mode ]] ||
           [[ "$filename" =~ ^Memory/limits.conf ]]; then
            continue # leave behavior for these undefined
        fi

        if ! echo "$expected_filenames" | grep -q "^$filename\$"; then
            retval=1
            echo "Found extra file: $filename"
        fi
    done

    rm -rf "$tarball" "$(basename "$tarball" .tar.gz)"

    if [ "$retval" -eq 0 ]; then
        echo 'PASSED'
    else
        echo 'FAILED'
    fi
    return "$retval"
}

# Read in options
options_list='infiniband,ib-ext,nvidia,nvidia-ext,dcgm,stream'
if ! PARSED_OPTIONS=$(getopt -n "$0" -o '' --long "$options_list"  -- "$@"); then
        echo "$HELP_MESSAGE"
        exit 1
fi
eval set -- "$PARSED_OPTIONS"

while [ "$1" != "--" ]; do
  case "$1" in
    --infiniband) INFINIBAND_PRESENT=true;;
    --ib-ext) INFINIBAND_EXT_PRESENT=true;;
    --nvidia) NVIDIA_PRESENT=true;;
    --nvidia-ext) NVIDIA_EXT_PRESENT=true;;
    --dcgm) DCGM_INSTALLED=true;;
    --stream) STREAM_ENABLED=true;;
  esac
  shift
done
shift

if [ "$INFINIBAND_PRESENT" = true ];then
    BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$INFINIBAND_FILENAMES"))
fi

if [ "$INFINIBAND_EXT_PRESENT" = true ];then
    BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$INFINIBAND_EXT_FILENAMES"))
fi

if [ "$INFINIBAND_EXT_PRESENT" = true ] ||
    [ "$INFINIBAND_PRESENT" = true ] ||
    [ -n "$IB_DEVICE_LIST" ];then
    BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$INFINIBAND_FOLDER"))
fi

if [ "$NVIDIA_EXT_PRESENT" = true ];then
    BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$NVIDIA_EXT_FILENAMES"))
fi

if [ "$NVIDIA_PRESENT" = true ];then
    BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$NVIDIA_FILENAMES"))
    if [ "$DCGM_INSTALLED" = true ];then
        BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$DCGM_FILENAMES"))
    fi
fi

if [ "$NVIDIA_EXT_PRESENT" = true ] || [ "$NVIDIA_PRESENT" = true ];then
    BASE_FILENAMES=$(cat <(echo "$BASE_FILENAMES") <(echo "$NVIDIA_FOLDER"))
fi

overall_retcode=0

# zero-output runs
echo 'Testing without sudo'
if [ "$(whoami)" = root ]; then
    user=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 8)
    while compgen -u | grep "$user"; do
        user=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 8)
    done
    useradd --system --no-create-home "$user"
    tmp=$(mktemp)
    cp "$HPC_DIAG" "$tmp"
    chmod 777 "$tmp"
    output=$(sudo -u "$user" bash "$tmp" --no-update)
    retcode=$?
    rm "$tmp"
    userdel "$user"
else
    output=$(bash "$HPC_DIAG" --no-update)
    retcode=$?
fi
if [ $retcode -eq 0 ]; then
    echo 'FAILED'
    overall_retcode=1
else
    echo 'PASSED'
fi

HPC_DIAG_URL='https://raw.githubusercontent.com/Azure/azhpc-diagnostics/main/Linux/src/gather_azhpc_vm_diagnostics.sh'
main=$(mktemp)
curl -s "$HPC_DIAG_URL" > "$main"
corrupted=$(mktemp)
sed <"$HPC_DIAG" '/VERSION_INFO=/c VERSION_INFO=dummy' >"$corrupted"
echo 'Testing auto-update'
if [ "$(yes | bash "$corrupted" --version)" != "$(bash "$main" --version)" ]; then
    echo 'FAILED'
    overall_retcode=1
else
    echo 'PASSED'
fi

sed <"$HPC_DIAG" '/VERSION_INFO=/c VERSION_INFO=dummy' >"$tmp"
echo 'Testing auto-update disablement'
if [ "$(yes | bash "$tmp" --version --no-update)" != 'dummy' ]; then
    echo 'FAILED'
    overall_retcode=1
else
    echo 'PASSED'
fi

echo 'Testing with -V'
nosudo_basic_script_test -V

echo 'Testing with --version'
nosudo_basic_script_test --version

echo 'Testing with -h'
nosudo_basic_script_test -h

echo 'Testing with --help'
nosudo_basic_script_test --help

METADATA_URL='http://169.254.169.254/metadata/instance?api-version=2020-06-01'
if ! curl -s -H Metadata:true --connect-timeout 1 "$METADATA_URL"; then
    echo "Couldn't connect to Azure IMDS. Cutting tests short."
    exit 1
fi

# base version
echo 'Testing with sudo'
echo 'Testing with no options'
sudo_basic_script_test || overall_retcode=1

# raised mem level
echo 'Testing with --mem-level=1'
if [ "$STREAM_ENABLED" = true ];then
    sudo_basic_script_test --mem-level=1 "$MEMORY_FILENAMES" || overall_retcode=1
else
    sudo_basic_script_test --mem-level=1 || overall_retcode=1
fi

echo 'Testing with invalid arguments'
if yes | sudo bash "$HPC_DIAG" --mem-level=1 --offline 1>&2; then
    echo 'FAILED'
    overall_retcode=1
else
    echo 'PASSED'
fi

# raised gpu-level
echo 'Testing with --gpu-level=3'
sudo_basic_script_test --gpu-level=3 || overall_retcode=1

exit $overall_retcode


#!/bin/bash
set -ex

# set properties
source ./set_properties.sh

# install utils
./install_utils.sh

# install compilers
./install_gcc.sh

# install mellanox ofed
./install_mellanoxofed.sh

# install mpi libraries
./install_mpis.sh

# install nvidia gpu driver
./install_nvidiagpudriver.sh

# install AMD tuned libraries
./install_amd_libs.sh

# install Intel libraries
./install_intel_libs.sh

# Install NCCL
./install_nccl.sh

# Install NVIDIA docker container
$COMMON_DIR/../alma/alma-8.x/common/install_docker.sh

# Install DCGM
./install_dcgm.sh

# optimizations
./hpc-tuning.sh

# install persistent rdma naming
$COMMON_DIR/install_azure_persistent_rdma_naming.sh

# add udev rule
$COMMON_DIR/../alma/common/add-udev-rules.sh

# add interface rules
$COMMON_DIR/../alma/common/network-config.sh

# install diagnostic script
$COMMON_DIR/install_hpcdiag.sh

#install monitoring tools
$COMMON_DIR/../alma/common/install_monitoring_tools.sh

# install AMD libs
$COMMON_DIR/../alma/common/install_amd_libs.sh

# install Azure/NHC Health Checks
$COMMON_DIR/install_health_checks.sh

# copy test file
$COMMON_DIR/copy_test_file.sh

# disable cloud-init
$ALMA_COMMON_DIR/disable_cloudinit.sh

# SKU Customization
$COMMON_DIR/setup_sku_customizations.sh

# clear history
# Uncomment the line below if you are running this on a VM
# $COMMON_DIR/clear_history.sh


#!/bin/bash
set -ex

# Install DCGM
DCGM_VERSION=2.4.4
DCGM_URL=https://azhpcstor.blob.core.windows.net/azhpc-images-store/datacenter-gpu-manager-${DCGM_VERSION}-1-x86_64.rpm
$COMMON_DIR/download_and_verify.sh $DCGM_URL "1d8fbe97797fada8048a7832bfac4bc7d3ad661bb24163d21324965ae7e7817d"
rpm -i datacenter-gpu-manager-${DCGM_VERSION}-1-x86_64.rpm
sed -i "$ s/$/ datacenter-gpu-manager/" /etc/dnf/dnf.conf
rm -f datacenter-gpu-manager-${DCGM_VERSION}-1-x86_64.rpm
$COMMON_DIR/write_component_version.sh "DCGM" ${DCGM_VERSION}

# Create service for dcgm to launch on bootup
bash -c "cat > /etc/systemd/system/dcgm.service" <<'EOF'
[Unit]
Description=DCGM service

[Service]
User=root
PrivateTmp=false
ExecStart=/usr/bin/nv-hostengine -n
Restart=on-abort

[Install]
WantedBy=multi-user.target
EOF

systemctl enable dcgm
systemctl start dcgm


#!/bin/bash

MODULE_FILES_DIRECTORY=/usr/share/Modules/modulefiles

mkdir -p ${MODULE_FILES_DIRECTORY}

$COMMON_DIR/install_gcc-9.2.sh ${MODULE_FILES_DIRECTORY}


#!/bin/bash
set -ex

VERSION="5.8-1.0.1.1"
TARBALL="MLNX_OFED_LINUX-$VERSION-rhel8.6-x86_64.tgz"
MLNX_OFED_DOWNLOAD_URL=https://content.mellanox.com/ofed/MLNX_OFED-${VERSION}/$TARBALL
MOFED_FOLDER=$(basename ${MLNX_OFED_DOWNLOAD_URL} .tgz)

$COMMON_DIR/download_and_verify.sh $MLNX_OFED_DOWNLOAD_URL "f340317047cc815b0f41c3f3c52d2d83ddc7d81b29d9fff91abb859850f77945"
tar zxvf ${TARBALL}

KERNEL=( $(rpm -q kernel | sed 's/kernel\-//g') )
KERNEL=${KERNEL[-1]}
./${MOFED_FOLDER}/mlnxofedinstall --kernel $KERNEL --kernel-sources /usr/src/kernels/${KERNEL} --add-kernel-support --skip-repo --skip-unsupported-devices-check --without-fw-update --distro rhel8.6

# Issue: Module mlx5_ib belong to a kernel which is not a part of MLNX
# Resolution: set FORCE=1/ force-restart /etc/init.d/openibd
# This causes openibd to ignore the kernel difference but relies on weak-updates
# Restarting openibd
/etc/init.d/openibd force-restart
$COMMON_DIR/write_component_version.sh "MOFED" $VERSION

# exclude opensm from updates
sed -i "$ s/$/ opensm*/" /etc/dnf/dnf.conf

# cleanup downloaded files
rm -rf *.tgz
rm -rf -- */


#!/bin/bash
set -ex

# Load gcc
GCC_VERSION=gcc-9.2.0
export PATH=/opt/${GCC_VERSION}/bin:$PATH
export LD_LIBRARY_PATH=/opt/${GCC_VERSION}/lib64:$LD_LIBRARY_PATH
set CC=/opt/${GCC_VERSION}/bin/gcc
set GCC=/opt/${GCC_VERSION}/bin/gcc

INSTALL_PREFIX=/opt

# HPC-X v2.14
HPCX_VERSION="v2.14"
TARBALL="hpcx-${HPCX_VERSION}-gcc-MLNX_OFED_LINUX-5-redhat8-cuda11-gdrcopy2-nccl2.16-x86_64.tbz"
HPCX_DOWNLOAD_URL=https://azhpcstor.blob.core.windows.net/azhpc-images-store/${TARBALL}
HPCX_FOLDER=$(basename ${HPCX_DOWNLOAD_URL} .tbz)

$COMMON_DIR/download_and_verify.sh $HPCX_DOWNLOAD_URL "126d7dfd71a8e7095baea200c8be9ff9318ee41018fbef9ec6733a54023d6c60"
tar -xvf ${TARBALL}
mv ${HPCX_FOLDER} ${INSTALL_PREFIX}
HPCX_PATH=${INSTALL_PREFIX}/${HPCX_FOLDER}
$COMMON_DIR/write_component_version.sh "HPCX" $HPCX_VERSION

# exclude ucx from updates
sed -i "$ s/$/ ucx*/" /etc/dnf/dnf.conf

# Install platform independent MPIs
HCOLL_PATH=${HPCX_PATH}/hcoll
UCX_PATH=${HPCX_PATH}/ucx

# MVAPICH2 2.3.7
MV2_VERSION="2.3.7"
MV2_DOWNLOAD_URL=http://mvapich.cse.ohio-state.edu/download/mvapich/mv2/mvapich2-${MV2_VERSION}.tar.gz
$COMMON_DIR/download_and_verify.sh $MV2_DOWNLOAD_URL "c39a4492f4be50df6100785748ba2894e23ce450a94128181d516da5757751ae"
tar -xvf mvapich2-${MV2_VERSION}.tar.gz
cd mvapich2-${MV2_VERSION}
./configure --prefix=${INSTALL_PREFIX}/mvapich2-${MV2_VERSION} --enable-g=none --enable-fast=yes && make -j$(nproc) && make install
cd ..
$COMMON_DIR/write_component_version.sh "MVAPICH2" ${MV2_VERSION}

# OpenMPI 4.1.3
OMPI_VERSION="4.1.3"
OMPI_DOWNLOAD_URL=https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-${OMPI_VERSION}.tar.gz
$COMMON_DIR/download_and_verify.sh $OMPI_DOWNLOAD_URL "9c0fd1f78fc90ca9b69ae4ab704687d5544220005ccd7678bf58cc13135e67e0"
tar -xvf openmpi-${OMPI_VERSION}.tar.gz
cd openmpi-${OMPI_VERSION}
./configure --prefix=${INSTALL_PREFIX}/openmpi-${OMPI_VERSION} --with-ucx=${UCX_PATH} --with-hcoll=${HCOLL_PATH} --enable-mpirun-prefix-by-default --with-platform=contrib/platform/mellanox/optimized && make -j$(nproc) && make install
cd ..
$COMMON_DIR/write_component_version.sh "OMPI" ${OMPI_VERSION}

# exclude openmpi, perftest from updates
sed -i "$ s/$/ openmpi perftest/" /etc/dnf/dnf.conf

# Intel MPI 2021 (Update 7)
IMPI_2021_VERSION="2021.7.0"
IMPI_2021_DOWNLOAD_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18926/l_mpi_oneapi_p_${IMPI_2021_VERSION}.8711_offline.sh
$COMMON_DIR/download_and_verify.sh $IMPI_2021_DOWNLOAD_URL "4eb1e1487b67b98857bc9b7b37bcac4998e0aa6d1b892b2c87b003bf84fb38e9"
bash l_mpi_oneapi_p_${IMPI_2021_VERSION}.8711_offline.sh -s -a -s --eula accept
mv ${INSTALL_PREFIX}/intel/oneapi/mpi/${IMPI_2021_VERSION}/modulefiles/mpi ${INSTALL_PREFIX}/intel/oneapi/mpi/${IMPI_2021_VERSION}/modulefiles/impi
$COMMON_DIR/write_component_version.sh "IMPI_2021" ${IMPI_2021_VERSION}

# Setup module files for MPIs
mkdir -p /usr/share/Modules/modulefiles/mpi/

# HPC-X
cat << EOF >> /usr/share/Modules/modulefiles/mpi/hpcx-${HPCX_VERSION}
#%Module 1.0
#
#  HPCx ${HPCX_VERSION}
#
conflict        mpi
module load ${HPCX_PATH}/modulefiles/hpcx
EOF

# MVAPICH2
cat << EOF >> /usr/share/Modules/modulefiles/mpi/mvapich2-${MV2_VERSION}
#%Module 1.0
#
#  MVAPICH2 ${MV2_VERSION}
#
conflict        mpi
module load ${GCC_VERSION}
prepend-path    PATH            /opt/mvapich2-${MV2_VERSION}/bin
prepend-path    LD_LIBRARY_PATH /opt/mvapich2-${MV2_VERSION}/lib
prepend-path    MANPATH         /opt/mvapich2-${MV2_VERSION}/share/man
setenv          MPI_BIN         /opt/mvapich2-${MV2_VERSION}/bin
setenv          MPI_INCLUDE     /opt/mvapich2-${MV2_VERSION}/include
setenv          MPI_LIB         /opt/mvapich2-${MV2_VERSION}/lib
setenv          MPI_MAN         /opt/mvapich2-${MV2_VERSION}/share/man
setenv          MPI_HOME        /opt/mvapich2-${MV2_VERSION}
EOF

# OpenMPI
cat << EOF >> /usr/share/Modules/modulefiles/mpi/openmpi-${OMPI_VERSION}
#%Module 1.0
#
#  OpenMPI ${OMPI_VERSION}
#
conflict        mpi
module load ${GCC_VERSION}
prepend-path    PATH            /opt/openmpi-${OMPI_VERSION}/bin
prepend-path    LD_LIBRARY_PATH /opt/openmpi-${OMPI_VERSION}/lib
prepend-path    MANPATH         /opt/openmpi-${OMPI_VERSION}/share/man
setenv          MPI_BIN         /opt/openmpi-${OMPI_VERSION}/bin
setenv          MPI_INCLUDE     /opt/openmpi-${OMPI_VERSION}/include
setenv          MPI_LIB         /opt/openmpi-${OMPI_VERSION}/lib
setenv          MPI_MAN         /opt/openmpi-${OMPI_VERSION}/share/man
setenv          MPI_HOME        /opt/openmpi-${OMPI_VERSION}
EOF

#IntelMPI-v2021
cat << EOF >> /usr/share/Modules/modulefiles/mpi/impi_${IMPI_2021_VERSION}
#%Module 1.0
#
#  Intel MPI ${IMPI_2021_VERSION}
#
conflict        mpi
module load /opt/intel/oneapi/mpi/${IMPI_2021_VERSION}/modulefiles/impi
setenv          MPI_BIN         /opt/intel/oneapi/mpi/${IMPI_2021_VERSION}/bin
setenv          MPI_INCLUDE     /opt/intel/oneapi/mpi/${IMPI_2021_VERSION}/include
setenv          MPI_LIB         /opt/intel/oneapi/mpi/${IMPI_2021_VERSION}/lib
setenv          MPI_MAN         /opt/intel/oneapi/mpi/${IMPI_2021_VERSION}/man
setenv          MPI_HOME        /opt/intel/oneapi/mpi/${IMPI_2021_VERSION}
EOF

# Create symlinks for modulefiles
ln -s /usr/share/Modules/modulefiles/mpi/hpcx-${HPCX_VERSION} /usr/share/Modules/modulefiles/mpi/hpcx
ln -s /usr/share/Modules/modulefiles/mpi/mvapich2-${MV2_VERSION} /usr/share/Modules/modulefiles/mpi/mvapich2
ln -s /usr/share/Modules/modulefiles/mpi/openmpi-${OMPI_VERSION} /usr/share/Modules/modulefiles/mpi/openmpi
ln -s /usr/share/Modules/modulefiles/mpi/impi_${IMPI_2021_VERSION} /usr/share/Modules/modulefiles/mpi/impi-2021

# cleanup downloaded tarball for HPC-x
rm -rf *.tar.gz *offline.sh *.tbz
rm -rf -- */


#!/bin/bash
set -ex

# Setup microsoft packages repository for moby
# Download the repository configuration package
curl https://packages.microsoft.com/config/rhel/8/prod.repo > ./microsoft-prod.repo
# Copy the generated list to the sources.list.d directory
cp ./microsoft-prod.repo /etc/yum.repos.d/

yum repolist

../common/install_utils.sh


#!/bin/bash

export TOP_DIR=../../..
export COMMON_DIR=../../../common
export ALMA_COMMON_DIR=../../common
export TEST_DIR=../../../tests
export DISTRIBUTION=$(. /etc/os-release;echo $ID$VERSION_ID)


#!/bin/bash
set -ex

# set properties
source ./set_properties.sh

# install utils
./install_utils.sh

# install Lustre client
$ALMA_COMMON_DIR/install_lustre_client.sh "8"

# install compilers
./install_gcc.sh

# install mellanox ofed
./install_mellanoxofed.sh

# install mpi libraries
./install_mpis.sh

# install nvidia gpu driver
./install_nvidiagpudriver.sh

# install AMD tuned libraries
./install_amd_libs.sh

# install Intel libraries
./install_intel_libs.sh

# cleanup downloaded tarballs - clear some space
rm -rf *.tgz *.bz2 *.tbz *.tar.gz *.run *.deb *_offline.sh
rm -rf /tmp/MLNX_OFED_LINUX* /tmp/*conf*
rm -rf /var/intel/ /var/cache/*
rm -Rf -- */

# Install NCCL
./install_nccl.sh

# Install NVIDIA docker container
$COMMON_DIR/../alma/alma-8.x/common/install_docker.sh

# Install DCGM
./install_dcgm.sh

# optimizations
./hpc-tuning.sh

# install persistent rdma naming
$COMMON_DIR/install_azure_persistent_rdma_naming.sh

# add udev rule
$COMMON_DIR/../alma/common/add-udev-rules.sh

# add interface rules
$COMMON_DIR/../alma/common/network-config.sh

# install diagnostic script
$COMMON_DIR/install_hpcdiag.sh

#install monitoring tools
$COMMON_DIR/../alma/common/install_monitoring_tools.sh

# install Azure/NHC Health Checks
$COMMON_DIR/install_health_checks.sh

# copy test file
$COMMON_DIR/copy_test_file.sh

# disable cloud-init
$ALMA_COMMON_DIR/disable_cloudinit.sh

# SKU Customization
$COMMON_DIR/setup_sku_customizations.sh

# clear history
# Uncomment the line below if you are running this on a VM
# $COMMON_DIR/clear_history.sh


#!/bin/bash

$COMMON_DIR/../alma/alma-8.x/common/install_amd_libs.sh
$ALMA_COMMON_DIR/install_amd_libs.sh


#!/bin/bash
set -ex

DISTRIB_CODENAME=el8
LUSTRE_VERSION=2.15.1_24_g98d1cac
REPO_PATH=/etc/yum.repos.d/amlfs.repo

rpm --import https://packages.microsoft.com/keys/microsoft.asc

echo -e "[amlfs]" > ${REPO_PATH}
echo -e "name=Azure Lustre Packages" >> ${REPO_PATH}
echo -e "baseurl=https://packages.microsoft.com/yumrepos/amlfs-${DISTRIB_CODENAME}" >> ${REPO_PATH}
echo -e "enabled=1" >> ${REPO_PATH}
echo -e "gpgcheck=1" >> ${REPO_PATH}
echo -e "gpgkey=https://packages.microsoft.com/keys/microsoft.asc" >> ${REPO_PATH}
echo -e "exclude=lustre-client-dkms*" >> ${REPO_PATH}

dnf install -y kmod-lustre-client-$(uname -r)-${LUSTRE_VERSION}-1.${DISTRIB_CODENAME}.x86_64.rpm lustre-client-${LUSTRE_VERSION}-1.${DISTRIB_CODENAME}.x86_64.rpm

$COMMON_DIR/write_component_version.sh "LUSTRE" ${LUSTRE_VERSION}


#!/bin/bash
set -ex

VERSION="23.04-0.5.3.3"
TARBALL="MLNX_OFED_LINUX-$VERSION-rhel8.7-x86_64.tgz"
MLNX_OFED_DOWNLOAD_URL=https://content.mellanox.com/ofed/MLNX_OFED-${VERSION}/$TARBALL
MOFED_FOLDER=$(basename ${MLNX_OFED_DOWNLOAD_URL} .tgz)

$COMMON_DIR/download_and_verify.sh $MLNX_OFED_DOWNLOAD_URL "1b9edbce2c30e62a5bcb5de087411532048b0987fadc62297af3cf9c2c45f444"
tar zxvf ${TARBALL}

KERNEL=( $(rpm -q kernel | sed 's/kernel\-//g') )
KERNEL=${KERNEL[-1]}
./${MOFED_FOLDER}/mlnxofedinstall --kernel $KERNEL --kernel-sources /usr/src/kernels/${KERNEL} --add-kernel-support --skip-repo --skip-unsupported-devices-check --without-fw-update --distro rhel8.7

# Issue: Module mlx5_ib belong to a kernel which is not a part of MLNX
# Resolution: set FORCE=1/ force-restart /etc/init.d/openibd
# This causes openibd to ignore the kernel difference but relies on weak-updates
# Restarting openibd
/etc/init.d/openibd force-restart
$COMMON_DIR/write_component_version.sh "MOFED" $VERSION

# exclude opensm from updates
sed -i "$ s/$/ opensm*/" /etc/dnf/dnf.conf

# cleanup downloaded files
rm -rf *.tgz
rm -rf -- */


#!/bin/bash
set -ex

# Load gcc
GCC_VERSION=gcc-9.2.0
export PATH=/opt/${GCC_VERSION}/bin:$PATH
export LD_LIBRARY_PATH=/opt/${GCC_VERSION}/lib64:$LD_LIBRARY_PATH
set CC=/opt/${GCC_VERSION}/bin/gcc
set GCC=/opt/${GCC_VERSION}/bin/gcc

INSTALL_PREFIX=/opt

# HPC-X v2.15
HPCX_VERSION="v2.15"
TARBALL="hpcx-${HPCX_VERSION}-gcc-MLNX_OFED_LINUX-5-redhat8-cuda12-gdrcopy2-nccl2.17-x86_64.tbz"
HPCX_DOWNLOAD_URL=https://azhpcstor.blob.core.windows.net/azhpc-images-store/${TARBALL}
HPCX_FOLDER=$(basename ${HPCX_DOWNLOAD_URL} .tbz)

$COMMON_DIR/download_and_verify.sh $HPCX_DOWNLOAD_URL "0ca27ef0d6fa3d6be176f461977875030bc8cc130a784e216b1c23259c733e41"
tar -xvf ${TARBALL}
mv ${HPCX_FOLDER} ${INSTALL_PREFIX}
HPCX_PATH=${INSTALL_PREFIX}/${HPCX_FOLDER}
$COMMON_DIR/write_component_version.sh "HPCX" $HPCX_VERSION

# exclude ucx from updates
sed -i "$ s/$/ ucx*/" /etc/dnf/dnf.conf

# Setup module files for MPIs
mkdir -p /usr/share/Modules/modulefiles/mpi/

# HPC-X
cat << EOF >> /usr/share/Modules/modulefiles/mpi/hpcx-${HPCX_VERSION}
#%Module 1.0
#
#  HPCx ${HPCX_VERSION}
#
conflict        mpi
module load ${HPCX_PATH}/modulefiles/hpcx
EOF

# Create symlinks for modulefiles
ln -s /usr/share/Modules/modulefiles/mpi/hpcx-${HPCX_VERSION} /usr/share/Modules/modulefiles/mpi/hpcx

# Install platform independent MPIs
$ALMA_COMMON_DIR/install_mpis.sh ${GCC_VERSION} ${HPCX_PATH}

# cleanup downloaded tarball for HPC-x
rm -rf *.tbz


#!/bin/bash

# Disable some unneeded services by default (administrators can re-enable if desired)
systemctl disable wpa_supplicant
systemctl disable abrtd

../../common/hpc-tuning.sh


#!/bin/bash
set -ex

INSTALL_PREFIX=/opt/amd
mkdir -p ${INSTALL_PREFIX}

AOCL_VERSION="4.0"
TARBALL="aocl-linux-aocc-${AOCL_VERSION}.tar.gz"
AOCL_DOWNLOAD_URL=https://azhpcstor.blob.core.windows.net/azhpc-images-store/${TARBALL}
$COMMON_DIR/download_and_verify.sh $AOCL_DOWNLOAD_URL "c8000a66aaa2a257252cbb307732b4e66758b72b08f43b3723f4eb5404ba28c8"
tar -xvf ${TARBALL}

pushd aocl-linux-aocc-${AOCL_VERSION}
./install.sh -t amd -l blis fftw libflame -i lp64
cp -r amd/${AOCL_VERSION}/* ${INSTALL_PREFIX}
popd

# Setup module files for AMD Libraries
MODULE_FILES_DIRECTORY=/usr/share/Modules/modulefiles/amd
mkdir -p ${MODULE_FILES_DIRECTORY}

# fftw
cat << EOF >> ${MODULE_FILES_DIRECTORY}/aocl-${AOCL_VERSION}
#%Module 1.0
#
#  AOCL
#
prepend-path    LD_LIBRARY_PATH   ${INSTALL_PREFIX}/lib
setenv          AMD_FFTW_INCLUDE  ${INSTALL_PREFIX}/include
EOF

# Create symlinks for modulefiles
ln -s ${MODULE_FILES_DIRECTORY}/aocl-${AOCL_VERSION} ${MODULE_FILES_DIRECTORY}/aocl
$COMMON_DIR/write_component_version.sh "AOCL" ${AOCL_VERSION}

# cleanup downloaded files
rm -rf *tar.gz