For Linux, as a programmer, you probably want to make use of the libhugetlbfs which takes care of everything for you under the hood. (Note: It may not even be required, I do not know for sure, I still have to test).
It replaces all the functions that manage memory with its own version which will automatically switch to a huge page if/when possible. This will include malloc() and mmap() and others like fork() allocating a stack.
With Ubuntu, you can install the library this way:
sudo apt-get install libhugetlbfs-dev
You can then make use of functions such as get_huge_pages() if you definitely want to allocate a large buffer in a huge page. This is an equivalent to malloc(). With the library installed you should have the manual pages so for details you can do:
man get_huge_page
There is also an OS function, mincore(), which allows you to get the number of huge pages and small (4K) pages used by a region of memory. There is a sample using in the BSD code below (where the function comes from, it's a BSD thing). This is most certainly what you were looking for under Unices (although it may not be available on all Unix OSes, like IRIX, HP-UX, AIX... you'd have to check). Note that this function is always available. You do not need the libhugetlbfs library to use it. Note that under Linux it doesn't look like they set anything else than bit 0, meaning that you only know whether the page is resident or not and not the size of the page as in BSD.
I pretty much exclusively work under Linux. But for MS-Windows, this is called "Large Pages". They have docs here: https://docs.microsoft.com/en-us/windows/win32/memory/large-page-support
Finally the various BSD implementations call those "Super Pages" (macos therefore uses that interface). I found this page with a code sample showing how many super pages get used for a large malloc().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
int
main(int argc, char **argv)
{
size_t size, flags, i, super = 0, ordinary = 0;
void *addr;
char *vec;
if (argc != 2)
return (0);
size = atoi(argv[1]);
addr = malloc(size);
vec = malloc(size / 4096);
memset(addr, 0, size);
flags = mincore(addr, size, vec);
printf("addr %p len %d:\n", addr, size);
for (i = 0; i <= size / 4096; i++)
if (vec[i] & MINCORE_SUPER)
super++;
else
ordinary++;
printf("%d 4K blocks super-mapped, %d ordinary 4K pages\n",
super, ordinary);
return (0);
}
And some output of that FreeBSD code:
x23% ./a.out 1000000
addr 0x801006000 len 1000000:
0 4K blocks super-mapped, 245 ordinary 4K pages
x23% ./a.out 10000000
addr 0x801000000 len 10000000:
2048 4K blocks super-mapped, 394 ordinary 4K pages
x23% ./a.out 100000000000
addr 0x801000000 len 1215752192:
296448 4K blocks super-mapped, 367 ordinary 4K pages
As we can see, the first number represents "super mapped pages", meaning that it uses memory allocated in blocks of 2Mb or 1Gb or some other sizes depending on your OS and settings and it was automatically handled under the hood.
IMPORTANT: The memset() is important, it commits ALL the pages of the allocated memory. Without that call, the allocated pages may be 1 or 2...