This code takes a number as input on the command line and calls the heapOverflow() function that many times:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void heapOverflow()
{
unsigned *some_array = malloc(50000);
}
int main(int argc, char *argv[])
{
unsigned num_calls = atoi(argv[1]);
while (num_calls > 0)
{
heapOverflow();
num_calls--;
}
return 0;
}
On Linux Mint 17.1, running this with a large enough input (e.g. 10000000 in my case) freezes the system for a few minutes, before bash returns with "Killed", and then the system remains slow for a couple more minutes.
Why does the OS allow a process to take over memory to such a degree? Shouldn't the scheduler and memory manager work together to kill a process when it becomes clear that it will request too much heap memory? Or is there a situation in which giving all this memory to one process could be useful (i.e. could the process actually be doing useful work even while the rest of the system, or at least the X GUI system, is frozen?)
Why does the OS allow a process to take over memory to such a degree?
Because it is configured to do so.
The Linux kernel supports, among other features, per-process resource limits as standardized in POSIX.1-2008; see e.g. prlimit for a command-line access to these, and getrlimit()/setrlimit() for the C library interface.
In most Linux distributions, these limits are set by a Pluggable Authentication Module pam_limits in limits.conf.
The problem is, those limits are very task-specific. They vary a lot from system to system, and indeed even from user to user: some don't like their system to start paging (slow down like OP described) and would rather the process to fail; others prefer to wait for a while since they actually need the results from the resource-hungry process. Setting the limits is the responsibility of the system administrator.
I guess one could easily write a program that checks the current configuration (in particular, /proc/meminfo), and set the resource limits for a single-user desktop/laptop machine. However, you could just as well create a helper script, say /usr/local/bin/run-limited,
#!/bin/sh
exec prlimit --as=1073741824 --rss=262144 "$#"
so you can run any of your programs with address space limited to 1 GB and resident set size (amount of RAM actually used) to 256k pages.
Related
I am learning about VDSO, wrote a simple application which calls gettimeofday()
#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
struct timeval current_time;
if (gettimeofday(¤t_time, NULL) == -1)
printf("gettimeofday");
getchar();
exit(EXIT_SUCCESS);
}
ldd on the binary shows 'linux-vdso'
$ ldd ./prog
linux-vdso.so.1 (0x00007ffce147a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6ef9e8e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6efa481000)
I did a find for the libvdso library and there is no such library present in my file system.
sudo find / -name 'linux-vdso.so*'
Where is the library present?
It's a virtual shared object that doesn't have any physical file on the disk; it's a part of the kernel that's exported into every program's address space when it's loaded.
It's main purpose to make more efficient to call certain system calls (which would otherwise incur performance issues like this). The most prominent being gettimeofday(2).
You can read more about it here: http://man7.org/linux/man-pages/man7/vdso.7.html
find / -name '*vdso*.so*'
yields
/lib/modules/4.15.0-108-generic/vdso/vdso64.so
/lib/modules/4.15.0-108-generic/vdso/vdso32.so
/lib/modules/4.15.0-108-generic/vdso/vdsox32.so
linux-vdso.so is a virtual symbolic link to the bitness-compatible respective vdso*.so.
vDSO = virtual dynamic shared object
Note on vdsox32:
x32 is a Linux ABI which is kind of a mix between x86 and x64.
It uses 32-bit address size but runs in full 64-bit mode, including all 64-bit instructions and registers available.
Making system calls can be slow. In x86 32-bit systems, you can
trigger a software interrupt (int $0x80) to tell the kernel you
wish to make a system call. However, this instruction is
expensive: it goes through the full interrupt-handling paths in
the processor's microcode as well as in the kernel. Newer
processors have faster (but backward incompatible) instructions
to initiate system calls. Rather than require the C library to
figure out if this functionality is available at run time, the C
library can use functions provided by the kernel in the vDSO.
Note that the terminology can be confusing. On x86 systems, the
vDSO function used to determine the preferred method of making a
system call is named "__kernel_vsyscall", but on x86-64, the term
"vsyscall" also refers to an obsolete way to ask the kernel what
time it is or what CPU the caller is on.
One frequently used system call is gettimeofday(2). This system
call is called both directly by user-space applications as well
as indirectly by the C library. Think timestamps or timing loops
or polling—all of these frequently need to know what time it is
right now. This information is also not secret—any application
in any privilege mode (root or any unprivileged user) will get
the same answer. Thus the kernel arranges for the information
required to answer this question to be placed in memory the
process can access. Now a call to gettimeofday(2) changes from a
system call to a normal function call and a few memory accesses.
Also
You must not assume the vDSO is mapped at any particular location
in the user's memory map. The base address will usually be
randomized at run time every time a new process image is created
(at execve(2) time). This is done for security reasons, to prevent
"return-to-libc" attacks.
And
Since the vDSO is a fully formed ELF image, you can do symbol lookups
on it.
And also
If you are trying to call the vDSO in your own application rather than
using the C library, you're most likely doing it wrong.
as well as
Why does the vDSO exist at all? There are some system calls the
kernel provides that user-space code ends up using frequently, to
the point that such calls can dominate overall performance. This
is due both to the frequency of the call as well as the context-
switch overhead that results from exiting user space and entering
the kernel.
I want to use a program to read a variable with a given address in another program using c. Here is my code:
#include<stdio.h>
#include<stdlib.h>
volatile unsigned int *a;
int main(){
scanf("%d",&a);//input the pointer to the variable I want to read
while(1){
printf("%d\n",*a);
system("pause");
}
}
To test this program, I used another program to change the variable. This is the code.
#include<stdio.h>
volatile unsigned int a;
int main(){
printf("%d\n",&a);//output the pointer to the variable
while(1)scanf("%d",&a);
}
I run the second program first and then type the output of the variable into the first program. It's wired that every time I run the second program, I get the same output. And when I run the first program, I get the same value every time, despite I changed the variable in the second program. Why doesn't it work? My computer is 32-bit.
It is operating system specific, and you generally should avoid doing that -even when possible-. Prefer other inter-process communication facilities (e.g. pipes, sockets, message passing)
On most OSes, each process has its own address space in virtual memory, so a process A cannot change any data in process B. BTW, two processes can run simultaneously (on different cores) or quasi-simultaneously (with their tasks scheduled by the kernel), so sharing without care a variable does not make any sense.
Some OSes provide shared memory facilities, but then you should care about synchronization (e.g. with semaphores).
For Linux, read Advanced Linux Programming and shm_overview(7) & sem_overview(7)
Generally, you need to design and adapt both programs to make them communicate. For security reasons you don't want (and your OS kernel forbids) arbitrary processes to be able to glance in other processes' address space.
For example, you don't want your game software to be able to access your banking data in your browser without your consent.
Alternatively, merge the two programs into a single multi-threaded application. You'll be concerned by synchronization and probably would need to use mutexes. Read e.g. some POSIX threads tutorial.
See also MPI. BTW, you might use some database to share the common data (look into PostGreSQL, MongoDB, etc...) or adapt a client-server model
For some precise measurements, I would like to invalidate/flush all caches up to RAM (main memory), from the command line (so that the main program running time evaluation is not affected by this process). I have found the following (The first and last from here):
1. echo 3 > /proc/sys/vm/drop_caches
and I could build a (pre-executed) program with the following
2. #include <asm/cachectl.h>
int cacheflush(char *addr, int nbytes, int cache);
or I could finally do a
3. int main() {
const int size = 20*1024*1024; // Allocate 20M. Set much larger then L2
char *c = (char *)malloc(size);
for (int i = 0; i < 0xffff; i++)
for (int j = 0; j < size; j++)
c[j] = i*j;
}
My question is: for what I need to do, which version is best, and if it is #2, what is the address I should be giving it as a start address? My uname -a is Linux 3.2.0-33-generic #52-Ubuntu SMP Thu Oct 18 16:19:45 UTC 2012 i686
You're running on an operating system that will do other things behind your back. The operating system will handle interrupts, run various daemons in the background and do various maintenance tasks and potentially move your running process to a different cpu, etc.
Invalidating caches is the least of your worries and if your measurements have to be this accurate, you need to reevaluate the environment where you run your test. Even if you manage to get everything the operating system does under control (which basically means making your tested code part of the operating system), you still need to consider TLB behavior and branch prediction buffers (which will affect your performance more than caches), get control over SMM (which you typically can't unless you have control over your BIOS) and understand how the clocks you use for measuring really behave (I'd guess that a temperature difference of 10 degrees will affect your measurement more than having a clean cache).
In other words - forget it. A typical way to measure things realistically is to run it "enough" times and take an average (or minimum or maximum or median, depending on what you want to prove).
To add more: Your method number 1 flushes the filesystem caches and has nothing to do with data caches on the cpu. Number 2 I have no idea about, my linux flavour doesn't have it. Number 3 might work if you'd have perfect cache associativity on your cpu, which you don't and would have to make sure that the physical pages allocated by the operating system will touch every possible cache line, which you can't. You'd also have to make sure that you either execute it on the same cpu your test will run on, or on all cpus and nothing will get scheduled to run in between. Since you want to run this from the command line, your shell will stomp all over the caches long before your program runs (and the exec system call and filesystem operations won't help).
The only way to reliably clear caches on your architecture is the wbinvd instruction which you're not allowed to call because you're not the kernel and are not supposed to mess around with caches.
When writing in C, how can I tell how much stack space is available in memory when I launch a program? How about heap space?
How can I tell how much memory is being used during the execution of my program?
This is all Win32-specific (not really C-specific, all just OS API):
When a thread is created, it gets 1MB stack space by default, by that can be modified in whatever CreateThread API you use.
You can peek into the thread information block to find the actual stack info, but even though this is documented, this technique isn't officially supported, see http://en.wikipedia.org/wiki/Win32_Thread_Information_Block .
Also, for a 32-bit application, you can only address up to 2GB, so for an app that by design uses lots of memory, then the thing to watch out for is the total size of the process' virtual address space (committed + reserved), which includes all heap allocations. You can programmatically access the process' virtual memory with the GlobalMemoryStatusEx API, look at the ullTotalVirtual param for virtual address space. Once your process gets close to 1.8 or 1.9GB of VAS, then heap allocations and VirtualAlloc calls begin to fail. For "normal" apps, you don't have to worry about running out of VAS, but it's always good to check for fail allocs. Also, you shouldn't get a stack overflow, unless you have a bug, or a bad design.
There is a philosophy that when you need to ask these kinds of questions, for practical and not educational or informational reasons, then you are doing something seriously wrong.
If you are asking this for error-checking or to make sure your program has enough memory, ect... then don't wrorry about it, seriously. As for your programs memory, you can use the task manager (on windows) if this is just for debugging. If you need to know this in your program, I wouldn't count on any non-hacky solution.
Abstractions for a reason
Really, your program shouldn't have this as a concern. It is an OS concern, your problem should just be efficient with what it needs and let the OS do its job.
If you insist, you could look into /proc/meminfo, brk(), getrlimit() and setrlimit() (here are some docs) with the RLIMIT_STACK and RLIMIT_DATA values for approximations and rough-ishes.
#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main (int argc, char *argv[])
{
struct rlimit limit;
/* Get the stack limit. */
if (getrlimit(RLIMIT_STACK, &limit) != 0) {
printf("getrlimit() failed with errno=%d\n", errno);
exit(1);
}
printf("The stack soft limit is %llu\n", limit.rlim_cur);
printf("The stack hard limit is %llu\n", limit.rlim_max);
exit(0);
}
Modified from here also see man getrlimit on your system
If you state what and why you want to do this, someone may have a better method or way of doing what you want.
I'd like to obtain memory usage information for both per process and system wide. In Windows, it's pretty easy. GetProcessMemoryInfo and GlobalMemoryStatusEx do these jobs greatly and very easily. For example, GetProcessMemoryInfo gives "PeakWorkingSetSize" of the given process. GlobalMemoryStatusEx returns system wide available memory.
However, I need to do it on Linux. I'm trying to find Linux system APIs that are equivalent GetProcessMemoryInfo and GlobalMemoryStatusEx.
I found 'getrusage'. However, max 'ru_maxrss' (resident set size) in struct rusage is just zero, which is not implemented. Also, I have no idea to get system-wide free memory.
Current workaround for it, I'm using "system("ps -p %my_pid -o vsz,rsz");". Manually logging to the file. But, it's dirty and not convenient to process the data.
I'd like to know some fancy Linux APIs for this purpose.
You can see how it is done in libstatgrab.
And you can also use it (GPL)
Linux has a (modular) filesystem-interface for fetching such data from the kernel, thus being usable by nearly any language or scripting tool.
Memory can be complex. There's the program executable itself, presumably mmap()'ed in. Shared libraries. Stack utilization. Heap utilization. Portions of the software resident in RAM. Portions swapped out. Etc.
What exactly is "PeakWorkingSetSize"? It sounds like the maximum resident set size (the maximum non-swapped physical-memory RAM used by the process).
Though it could also be the total virtual memory footprint of the entire process (sum of the in-RAM and SWAPPED-out parts).
Irregardless, under Linux, you can strace a process to see its kernel-level interactions. "ps" gets its data from /proc/${PID}/* files.
I suggest you cat /proc/${PID}/status. The Vm* lines are quite useful.
Specifically: VmData refers to process heap utilization. VmStk refers to process stack utilization.
If you continue using "ps", you might consider popen().
I have no idea to get system-wide free memory.
There's always /usr/bin/free
Note that Linux will make use of unused memory for buffering files and caching... Thus the +/-buffers/cache line.