අවම ධාවනය කළ හැකි POSIX C උදාහරණ
දේවල් වඩාත් සංයුක්ත කිරීමට, time
අවම සී පරීක්ෂණ වැඩසටහන් කිහිපයක් සමඟ ආන්තික අවස්ථා කිහිපයක් නිදර්ශනය කිරීමට මට අවශ්යය .
සියලුම වැඩසටහන් සම්පාදනය කර ක්රියාත්මක කළ හැකිය:
gcc -ggdb3 -o main.out -pthread -std=c99 -pedantic-errors -Wall -Wextra main.c
time ./main.out
උබුන්ටු 18.10, GCC 8.2.0, glibc 2.28, ලිනක්ස් කර්නල් 4.18, ThinkPad P51 ලැප්ටොප්, Intel Core i7-7820HQ CPU (4 core / 8 threads), 2x Samsung M471A2K43BB1-CRC RAM (2x 16GiB) වලින් පරීක්ෂා කර ඇත.
නින්ද
කාර්යබහුල නොවන නින්ද එක්කෝ user
හෝ sys
පමණක් ගණන් නොගනී real
.
උදාහරණයක් ලෙස, තත්පරයක් නිදාගන්නා වැඩසටහනක්:
#define _XOPEN_SOURCE 700
#include <stdlib.h>
#include <unistd.h>
int main(void) {
sleep(1);
return EXIT_SUCCESS;
}
GitHub ඉහළට .
වැනි දෙයක් ප්රතිදානය කරයි:
real 0m1.003s
user 0m0.001s
sys 0m0.003s
IO ලබා ගැනීම අවහිර කරන ලද වැඩසටහන් සඳහා ද එයම වේ.
උදාහරණයක් ලෙස, පහත දැක්වෙන වැඩසටහන මඟින් පරිශීලකයාට අක්ෂරයක් ඇතුළත් කර බලා ඔබන්න:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("%c\n", getchar());
return EXIT_SUCCESS;
}
GitHub ඉහළට .
ඔබ තත්පරයක් පමණ බලා සිටියහොත්, එය නින්දේ උදාහරණය මෙන් ප්රතිදානය කරයි:
real 0m1.003s
user 0m0.001s
sys 0m0.003s
මෙම හේතුව නිසා time
ඔබට CPU සහ IO බැඳී ඇති වැඩසටහන් අතර වෙනස හඳුනාගත හැකිය: "CPU bound" සහ "I / O bound" යන වචනවල තේරුම කුමක්ද?
බහු නූල්
පහත දැක්වෙන උදාහරණයෙන් නූල් niters
මත වැඩ නොකරන තනිකරම CPU- බැඳී ඇති ක්රියාකාරකම් නැවත සිදු කරයි nthreads
:
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
uint64_t niters;
void* my_thread(void *arg) {
uint64_t *argument, i, result;
argument = (uint64_t *)arg;
result = *argument;
for (i = 0; i < niters; ++i) {
result = (result * result) - (3 * result) + 1;
}
*argument = result;
return NULL;
}
int main(int argc, char **argv) {
size_t nthreads;
pthread_t *threads;
uint64_t rc, i, *thread_args;
/* CLI args. */
if (argc > 1) {
niters = strtoll(argv[1], NULL, 0);
} else {
niters = 1000000000;
}
if (argc > 2) {
nthreads = strtoll(argv[2], NULL, 0);
} else {
nthreads = 1;
}
threads = malloc(nthreads * sizeof(*threads));
thread_args = malloc(nthreads * sizeof(*thread_args));
/* Create all threads */
for (i = 0; i < nthreads; ++i) {
thread_args[i] = i;
rc = pthread_create(
&threads[i],
NULL,
my_thread,
(void*)&thread_args[i]
);
assert(rc == 0);
}
/* Wait for all threads to complete */
for (i = 0; i < nthreads; ++i) {
rc = pthread_join(threads[i], NULL);
assert(rc == 0);
printf("%" PRIu64 " %" PRIu64 "\n", i, thread_args[i]);
}
free(threads);
free(thread_args);
return EXIT_SUCCESS;
}
GitHub upstream + plot code .
මගේ හයිපර්ට්රෙඩ් සීපීයූ 8 හි ස්ථාවර 10 ^ 10 පුනරාවර්තන සඳහා නූල් ගණනක ශ්රිතයක් ලෙස අපි බිත්ති, පරිශීලක සහ සයිස් සැලසුම් කරමු:
දත්ත සැලසුම් කරන්න .
ප්රස්ථාරයෙන් අපට එය පෙනේ:
CPU තීව්ර තනි මූලික යෙදුමක් සඳහා, බිත්තිය සහ පරිශීලකයා එක සමාන වේ
මධ්ය 2 ක් සඳහා, පරිශීලකයා බිත්ති 2x ක් පමණ වේ, එයින් අදහස් කරන්නේ පරිශීලක කාලය සියලු නූල් හරහා ගණනය කරන බවයි.
පරිශීලකයා මූලික වශයෙන් දෙගුණයක් වූ අතර බිත්තිය එලෙසම පැවතුනි.
මෙය මගේ පරිගණකයේ ඇති හයිපර්ට්රෙඩ් ගණනට ගැලපෙන නූල් 8 ක් දක්වා පවතී.
8 න් පසු, බිත්තියද වැඩි වීමට පටන් ගනී, මන්ද අපට යම් කාලයක් තුළ වැඩි වැඩ කොටසක් කිරීමට අමතර CPU නොමැති නිසාය!
මෙම අවස්ථාවෙහිදී සානුව අනුපාතය.
මෙම ප්රස්ථාරය එතරම් පැහැදිලි හා සරල බව මතක තබා ගන්න, මන්දයත් එය තනිකරම CPU- බැඳී ඇති හෙයිනි: එය මතක ශක්තියෙන් බැඳී තිබුනේ නම්, අඩු කාර්ය සාධනයක් සහිතව අපට බොහෝ කලකට පෙර කාර්ය සාධනය අඩුවනු ඇත, මන්ද මතක ප්රවේශයන් බාධකයක් වනු ඇත්තේ කුමක් ද? "CPU bound" සහ "I / O bound" යන වචන වලින් අදහස් වේද?
Sys බර වැඩ සමඟ sendfile
මට ඉදිරිපත් කළ හැකි බරම sys කාර්ය භාරය වූයේ sendfile
කර්නල් අවකාශයේ ගොනු පිටපත් කිරීමේ ක්රියාවලියක් භාවිතා කිරීමයි: ගොනුවක් ඉතා සුරක්ෂිතව හා කාර්යක්ෂමව පිටපත් කරන්න
ඉතින් මම හිතුවා මේ කර්නලය memcpy
CPU තීව්ර මෙහෙයුමක් වේවි කියලා.
පළමුව මම විශාල 10GiB අහඹු ගොනුවක් ආරම්භ කරන්නේ:
dd if=/dev/urandom of=sendfile.in.tmp bs=1K count=10M
ඉන්පසු කේතය ධාවනය කරන්න:
#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv) {
char *source_path, *dest_path;
int source, dest;
struct stat stat_source;
if (argc > 1) {
source_path = argv[1];
} else {
source_path = "sendfile.in.tmp";
}
if (argc > 2) {
dest_path = argv[2];
} else {
dest_path = "sendfile.out.tmp";
}
source = open(source_path, O_RDONLY);
assert(source != -1);
dest = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
assert(dest != -1);
assert(fstat(source, &stat_source) != -1);
assert(sendfile(dest, source, 0, stat_source.st_size) != -1);
assert(close(source) != -1);
assert(close(dest) != -1);
return EXIT_SUCCESS;
}
GitHub ඉහළට .
එමඟින් මූලික වශයෙන් බොහෝ දුරට පද්ධති කාලය අපේක්ෂිත පරිදි ලබා දෙයි:
real 0m2.175s
user 0m0.001s
sys 0m1.476s
time
විවිධ ක්රියාදාමයන්හි අන්තරායන් අතර වෙනස හඳුනාගත හැකිදැයි බැලීමට මට කුතුහලයක් ඇති විය , එබැවින් මම උත්සාහ කළෙමි:
time ./sendfile.out sendfile.in1.tmp sendfile.out1.tmp &
time ./sendfile.out sendfile.in2.tmp sendfile.out2.tmp &
ප්රති result ලය වූයේ:
real 0m3.651s
user 0m0.000s
sys 0m1.516s
real 0m4.948s
user 0m0.000s
sys 0m1.562s
තනි ක්රියාවලියක් සඳහා sys කාලය දෙකටම සමාන වේ, නමුත් බිත්ති කාලය විශාල වන්නේ ක්රියාදාමයන් තැටි කියවීමේ ප්රවේශය සඳහා තරඟ කරන බැවිනි.
එබැවින් දී ඇති කර්නල් කාර්යයක් ආරම්භ කළේ කුමන ක්රියාවලිය සඳහාද යන්න ඇත්ත වශයෙන්ම ගණනය කරන බව පෙනේ.
මූලාශ්ර කේතය
ඔබ time <cmd>
උබුන්ටු මත පමණක් කරන විට , එය දැක ගත හැකි පරිදි Bash යතුරු පදය භාවිතා කරයි:
type time
කුමන ප්රතිදානයන්:
time is a shell keyword
එබැවින් අපි ප්රතිදාන නූල සඳහා Bash 4.19 ප්රභව කේතයෙන් ප්රභවය ලබා ගනිමු:
git grep '"user\b'
එය අපව execute_cmd.c ශ්රිතයට time_command
යොමු කරයි, එය භාවිතා කරන්නේ:
gettimeofday()
හා getrusage()
දෙකම ලබා ගත හැකි නම්,
times()
නැතිනම්
ඒ සියල්ල ලිනක්ස් පද්ධති ඇමතුම් සහ පොසික්ස් කාර්යයන් වේ.
GNU Coreutils ප්රභව කේතය
අපි එය මෙසේ නම්:
/usr/bin/time
ඉන්පසු එය GNU Coreutils ක්රියාත්මක කිරීම භාවිතා කරයි.
මෙය ටිකක් සංකීර්ණයි, නමුත් අදාළ ප්රභවය resuse.c හි ඇති බව පෙනේ .
- POSIX නොවන BSD
wait3
ඇමතුමක් තිබේ නම්
times
සහ gettimeofday
වෙනත් ආකාරයකින්