diff --git a/Source/MemTesterNX/.gitignore b/Source/MemTesterNX/.gitignore deleted file mode 100644 index 3044e05c..00000000 --- a/Source/MemTesterNX/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.DS_Store -build/ -*.elf -*.nacp -*.nro \ No newline at end of file diff --git a/Source/MemTesterNX/LICENSE b/Source/MemTesterNX/LICENSE deleted file mode 100644 index d159169d..00000000 --- a/Source/MemTesterNX/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Source/MemTesterNX/Makefile b/Source/MemTesterNX/Makefile deleted file mode 100644 index 8534105f..00000000 --- a/Source/MemTesterNX/Makefile +++ /dev/null @@ -1,222 +0,0 @@ -#--------------------------------------------------------------------------------- -.SUFFIXES: -#--------------------------------------------------------------------------------- - -ifeq ($(strip $(DEVKITPRO)),) -$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") -endif - -TOPDIR ?= $(CURDIR) -include $(DEVKITPRO)/libnx/switch_rules - -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# DATA is a list of directories containing data files -# INCLUDES is a list of directories containing header files -# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) -# -# NO_ICON: if set to anything, do not use icon. -# NO_NACP: if set to anything, no .nacp file is generated. -# APP_TITLE is the name of the app stored in the .nacp file (Optional) -# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) -# APP_VERSION is the version of the app stored in the .nacp file (Optional) -# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) -# ICON is the filename of the icon (.jpg), relative to the project folder. -# If not set, it attempts to use one of the following (in this order): -# - .jpg -# - icon.jpg -# - /default_icon.jpg -# -# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder. -# If not set, it attempts to use one of the following (in this order): -# - .json -# - config.json -# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead -# of a homebrew executable (.nro). This is intended to be used for sysmodules. -# NACP building is skipped as well. -#--------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) -BUILD := build -SOURCES := source -DATA := data -INCLUDES := include -#ROMFS := romfs - -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- -ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE -fPIC - -CFLAGS := -g -Wall -O2 -ffunction-sections \ - $(ARCH) $(DEFINES) - -CFLAGS += $(INCLUDE) -D__SWITCH__ - -CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions - -ASFLAGS := -g $(ARCH) -LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) - -LIBS := -lnx - -#--------------------------------------------------------------------------------- -# list of directories containing libraries, this must be the top level containing -# include and lib -#--------------------------------------------------------------------------------- -LIBDIRS := $(PORTLIBS) $(LIBNX) - - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- - -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -export DEPSDIR := $(CURDIR)/$(BUILD) - -CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- - -export OFILES_BIN := $(addsuffix .o,$(BINFILES)) -export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export OFILES := $(OFILES_BIN) $(OFILES_SRC) -export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) - -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif - -ifeq ($(strip $(ICON)),) - icons := $(wildcard *.jpg) - ifneq (,$(findstring $(TARGET).jpg,$(icons))) - export APP_ICON := $(TOPDIR)/$(TARGET).jpg - else - ifneq (,$(findstring icon.jpg,$(icons))) - export APP_ICON := $(TOPDIR)/icon.jpg - endif - endif -else - export APP_ICON := $(TOPDIR)/$(ICON) -endif - -ifeq ($(strip $(NO_ICON)),) - export NROFLAGS += --icon=$(APP_ICON) -endif - -ifeq ($(strip $(NO_NACP)),) - export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp -endif - -ifneq ($(APP_TITLEID),) - export NACPFLAGS += --titleid=$(APP_TITLEID) -endif - -ifneq ($(ROMFS),) - export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) -endif - -.PHONY: $(BUILD) clean all - -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... -ifeq ($(strip $(APP_JSON)),) - @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf -else - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf -endif - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -ifeq ($(strip $(APP_JSON)),) - -all : $(OUTPUT).nro - -ifeq ($(strip $(NO_NACP)),) -$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp -else -$(OUTPUT).nro : $(OUTPUT).elf -endif - -else - -all : $(OUTPUT).nsp - -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm - -$(OUTPUT).nso : $(OUTPUT).elf - -endif - -$(OUTPUT).elf : $(OFILES) - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Source/MemTesterNX/source/main.c b/Source/MemTesterNX/source/main.c deleted file mode 100644 index 12dc8ae7..00000000 --- a/Source/MemTesterNX/source/main.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * MemTesterNX - * based on memtester version 4 - * - * Very simple but very effective user-space memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2020 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - */ - - #define __version__ "4.5.1-multithread" - - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include // for int64_t etc - - #include "types.h" - #include "sizes.h" - #include "tests.h" - #include - - /* Some helpful typedefs used throughout the file (used by original code) */ - typedef unsigned long long ull; - typedef unsigned long ul; - - /* number of bits in a machine word printed in the header */ - #define MACHINE_BITS ((int)(sizeof(void*) * 8)) - - PadState pad; - unsigned short dividend = 1; - - void waitForAnyKey() { - while (appletMainLoop()) - { - padUpdate(&pad); - - u64 kDown = padGetButtonsDown(&pad); - - if (kDown) - break; - - consoleUpdate(NULL); - } - } - - void ShowErr(const char* err, const char* details, Result rc) { - AppletStorage errStor; - LibAppletArgs args; - AppletHolder currentApplet; - - appletCreateLibraryApplet(¤tApplet, AppletId_LibraryAppletError, LibAppletMode_AllForeground); - libappletArgsCreate(&args, 1); - libappletArgsPush(&args, ¤tApplet); - appletCreateStorage(&errStor, 0x1018); - u8 argBuf[0x1018] = {0}; - argBuf[0] = 1; - - /* keep existing packing used by original code */ - *(u64*)&argBuf[8] = (((rc & 0x1ffu) + 2000) | (((rc >> 9) & 0x1fff & 0x1fffll) << 32)); - strcpy((char*) &argBuf[24], err); - strcpy((char*) &argBuf[0x818], details); - appletStorageWrite(&errStor, 0, argBuf, 0x1018); - appletHolderPushInData(¤tApplet, &errStor); - - appletHolderStart(¤tApplet); - appletHolderJoin(¤tApplet); - appletHolderClose(¤tApplet); - appletHolderRequestExit(¤tApplet); - } - - double gettime(void) - { - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.; - } - - struct test tests[] = { - { "Random Value", test_random_value }, - { "Compare XOR", test_xor_comparison }, - { "Compare SUB", test_sub_comparison }, - { "Compare MUL", test_mul_comparison }, - { "Compare DIV", test_div_comparison }, - { "Compare OR", test_or_comparison }, - { "Compare AND", test_and_comparison }, - { "Sequential Increment", test_seqinc_comparison }, - { "Solid Bits", test_solidbits_comparison }, - { "Block Sequential", test_blockseq_comparison }, - { "Checkerboard", test_checkerboard_comparison }, - { "Bit Spread", test_bitspread_comparison }, - { "Bit Flip (Slow)", test_bitflip_comparison }, - { "Walking Ones", test_walkbits1_comparison }, - { "Walking Zeroes", test_walkbits0_comparison }, - #ifdef TEST_NARROW_WRITES - { "8-bit Writes", test_8bit_wide_random }, - { "16-bit Writes", test_16bit_wide_random }, - #endif - { NULL, NULL } - }; - - struct test stress_tests[] = { - { "Stress memcpy x128", test_stress_memcpy }, - { "Stress memset x128", test_stress_memset }, - { "Stress memcmp x 32", test_stress_memcmp }, - { NULL, NULL } - }; - - int memtester_pagesize(void) { - printf("using pagesize of 4096\n"); - return 4096; - } - - /* Global vars - so tests have access to this information */ - int use_phys = 0; - off_t physaddrbase = 0; - int testJobId[4] = {0}; - int testWorkerReport[4] = {0}; - size_t bufsize[4], wantbytes[4]; - void volatile *aligned[4]; - Thread threads[5]; - struct test* test_select = tests; - - void testWorker(int div) - { - /* Wait until main sets this worker to ready (-2) */ - while (testJobId[div] != -2) - svcSleepThread(10000000ULL); - - while (true) - { - int currentJobId = -1; - - /* Wait until main moves us to the stuck-address job (-1) */ - while (testJobId[div] != currentJobId) - svcSleepThread(10000000ULL); - - /* Stuck address test: bufsize is in bytes, test_stuck_address expects count in ul units */ - if (!test_stuck_address(aligned[div], bufsize[div] / sizeof(ul))) - { - testWorkerReport[div] = 1; - currentJobId++; - } - else - { - testWorkerReport[div] = -1; - return; - } - - /* Now iterate over the selected tests */ - while (test_select[currentJobId].name) - { - while (testJobId[div] != currentJobId) - svcSleepThread(10000000ULL); - - /* Ensure second pointer argument is a pointer (not integer) */ - void volatile *second_ptr = (void volatile *)((size_t)aligned[div] + bufsize[div] / 2); - int test_rc = test_select[currentJobId].fp(aligned[div], second_ptr, (bufsize[div] / sizeof(ul)) / 2); - if (!test_rc) - { - testWorkerReport[div] = 1; - currentJobId++; - } - else - { - testWorkerReport[div] = -1; - return; - } - } - } - } - - void testWorker0(void*) { testWorker(0); } - void testWorker1(void*) { testWorker(1); } - void testWorker2(void*) { testWorker(2); } - void testWorker3(void*) { testWorker(3); } - - void* workers[] = { - testWorker0, - testWorker1, - testWorker2, - testWorker3, - }; - - void LblUpdate() - { - smInitialize(); - lblInitialize(); - LblBacklightSwitchStatus lblstatus = LblBacklightSwitchStatus_Disabled; - lblGetBacklightSwitchStatus(&lblstatus); - if (lblstatus) { - lblSwitchBacklightOff(0); - } else { - lblSwitchBacklightOn(0); - } - lblExit(); - smExit(); - } - - void keyListener() - { - while (true) - { - padUpdate(&pad); - u64 kDown = padGetButtonsDown(&pad); - if (kDown & HidNpadButton_Minus) - { - LblUpdate(); - } - svcSleepThread(10000000ULL); - } - } - - // Main program entrypoint - int main(int argc, char* argv[]) - { - if(appletGetAppletType() != AppletType_Application) { - ShowErr("Running in applet mode\nMemTesterNX requires full memory mode.\nPlease launch hbmenu by holding R on an APP (e.g. a game) NOT an applet (e.g. Gallery)", "", 0); - return 0; - } - - appletReportUserIsActive(); - - consoleInit(NULL); - - padConfigureInput(1, HidNpadStyleSet_NpadStandard); - - padInitializeDefault(&pad); - - ull loop; - size_t i; - unsigned short div, testThreads = 3; - size_t pagesize, wantraw, wantbytes_orig; - ptrdiff_t pagesizemask; - void volatile *buf[4]; - int memshift; - ull totalmem = 0; - int numOfMallocs = 0; - bool isDevKit8GB = false; - - printf("MemTesterNX version " __version__ " (%d-bit)\n"\ - "Based on memtester. Copyright (C) 2001-2020 Charles Cazabon, 2021 KazushiMe.\n"\ - "Licensed under the GNU General Public License version 2 (only).\n\n"\ - "Support full RAM test (up to 8GB) with 3-4 threads.\n"\ - "It will be looping forever until error occurs or user exits to HOME screen.\n\n"\ - "Press A: long test\n"\ - "Press X: fast test\n"\ - "Press Y: stress DRAM (memcpy, memset and memcmp)\n"\ - "Press any other key: exit\n\n", - MACHINE_BITS); - - while (appletMainLoop()) - { - padUpdate(&pad); - - u64 kDown = padGetButtonsDown(&pad); - - if (kDown & HidNpadButton_A) - { - break; - } - else if (kDown & HidNpadButton_X) - { - dividend = 4; - break; - } - else if (kDown & HidNpadButton_Y) - { - dividend = 16; - test_select = stress_tests; - break; - } - else if (kDown) - { - consoleExit(NULL); - exit(0); - } - - consoleUpdate(NULL); - } - - // Disable auto sleep and request CPU Boost mode - appletSetAutoSleepDisabled(true); - appletSetCpuBoostMode(ApmCpuBoostMode_FastLoad); - - pagesize = memtester_pagesize(); - pagesizemask = (ptrdiff_t) ~(pagesize - 1); - printf("pagesizemask is 0x%tx\n", pagesizemask); - consoleUpdate(NULL); - - memshift = 20; /* megabytes */ - wantraw = 2048; // HOS limit - - wantbytes_orig = ((size_t) wantraw << memshift); - - // Allocate as much RAM as possible. - for (div = 0; div <= 3; div++) - { - buf[div] = NULL; - wantbytes[div] = wantbytes_orig; - - while (!buf[div] && wantbytes[div]) { - buf[div] = (void volatile *) malloc(wantbytes[div]); - if (!buf[div]) - wantbytes[div] -= pagesize; - } - - totalmem += wantbytes[div]; - - if ((wantbytes[div] >> memshift) < 2047) - { - numOfMallocs = div + 1; - break; - } - } - - for (div = 0; div < numOfMallocs; div++) - { - free((void *)buf[div]); - } - - // Unknown: Not sure if devkit could use full 8GB in application space - if ((totalmem >> memshift) > 3 * 2047) - { - isDevKit8GB = true; - testThreads = 4; - } - - // Create workers - for (div = 0; div < testThreads; div++) - { - Result rc; - rc = threadCreate(&threads[div], workers[div], NULL, NULL, 0x1000, 0x2C, div == 3 ? -2 : div); - if (R_FAILED(rc)) - { - printf("Fatal: threadCreate[%d] failed: 0x%X\n", div, rc); - consoleUpdate(NULL); - } - else - { - totalmem -= 0x1000; - } - } - - // keyListener - { - const int kl = testThreads; - Result rc = threadCreate(&threads[kl], keyListener, NULL, NULL, 0x1000, 0x20, -2); - if (R_FAILED(rc)) - { - printf("Fatal: threadCreate[%d] failed: 0x%X\n", kl, rc); - consoleUpdate(NULL); - } - threadStart(&threads[kl]); - } - - printf("\nTotal RAM available: %lluMB\n\n", (unsigned long long)(totalmem >> memshift)); - consoleUpdate(NULL); - - // Redistribute RAM allocation equally to testThreads workers - for (div = 0; div < testThreads; div++) - { - buf[div] = NULL; - if (isDevKit8GB) - { - if (div != 3) - wantbytes[div] = totalmem / 3; - else - wantbytes[div] = 2047 << memshift; /* convert MB to bytes */ - } - else - { - wantbytes[div] = totalmem / testThreads; - } - - while (!buf[div] && wantbytes[div]) { - buf[div] = (void volatile *) malloc(wantbytes[div]); - if (!buf[div]) - wantbytes[div] -= pagesize; - } - - bufsize[div] = wantbytes[div]; - - /* Do alignment here as well */ - if ((size_t) buf[div] % pagesize) { - aligned[div] = (void volatile *) (((size_t) buf[div] & pagesizemask) + pagesize); - bufsize[div] -= ((size_t) aligned[div] - (size_t) buf[div]); - } else { - aligned[div] = buf[div]; - } - - printf("Alloc %d: got %lluMB (%llu bytes)\n", div+1, (unsigned long long)(wantbytes[div] >> memshift), (unsigned long long)wantbytes[div]); - consoleUpdate(NULL); - } - - // Start workers - for (div = 0; div < testThreads; div++) - { - Result rc; - rc = threadStart(&threads[div]); - if (R_FAILED(rc)) - { - printf("Fatal: threadStart[%d] failed: 0x%X\n", div, rc); - consoleUpdate(NULL); - } - } - - for(loop=1;;loop++) - { - // Set testJobId to -2 (Ready) - for (int j = 0; j < testThreads; j++) - testJobId[j] = -2; - - printf("Loop %llu:\n", (unsigned long long)loop); - - // Stuck address (-1) - printf(" %-20s: ", "Stuck Address"); - consoleUpdate(NULL); - for (int j = 0; j < testThreads; j++) - testJobId[j] = -1; - - for (int j = 0; j < testThreads; ) - { - switch (testWorkerReport[j]) - { - case 0: - svcSleepThread(10000000ULL); - break; - case -1: - printf("Alloc %d/%d: Error detected!\nPress any key to exit.\n", j+1, testThreads); - consoleUpdate(NULL); - waitForAnyKey(); - consoleExit(NULL); - return 0; - case 1: - testWorkerReport[j] = 0; - j++; - continue; - } - } - printf("ok\n"); - consoleUpdate(NULL); - - // tests[] - for (i = 0 ;; i++) { - if (!test_select[i].name) - break; - - printf(" %-20s: ...", test_select[i].name); - consoleUpdate(NULL); - for (int j = 0; j < testThreads; j++) - testJobId[j] = (int)i; - - double start_sec = gettime(); - for (int j = 0; j < testThreads; ) - { - switch (testWorkerReport[j]) - { - case 0: - svcSleepThread(10000000ULL); - continue; - case -1: - printf("Alloc %d/%d: Error detected!\nPress any key to exit.\n", j+1, testThreads); - consoleUpdate(NULL); - waitForAnyKey(); - consoleExit(NULL); - return 0; - case 1: - testWorkerReport[j] = 0; - j++; - continue; - } - } - double end_sec = gettime(); - printf("\b\b\bok! finished in %.1fs\n", end_sec - start_sec); - consoleUpdate(NULL); - } - } - - // Deinitialize and clean up resources used by the console (important!) - consoleExit(NULL); - return 0; - } - \ No newline at end of file diff --git a/Source/MemTesterNX/source/memtester.h b/Source/MemTesterNX/source/memtester.h deleted file mode 100755 index 2116eb86..00000000 --- a/Source/MemTesterNX/source/memtester.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Very simple (yet, for some reason, very effective) memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2020 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - * This file contains the declarations for external variables from the main file. - * See other comments in that file. - * - */ - -#include - -/* extern declarations. */ - -extern int use_phys; -extern off_t physaddrbase; - diff --git a/Source/MemTesterNX/source/sizes.h b/Source/MemTesterNX/source/sizes.h deleted file mode 100755 index cd1c3adc..00000000 --- a/Source/MemTesterNX/source/sizes.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Very simple but very effective user-space memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2012 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - * This file contains some macro definitions for handling 32/64 bit platforms. - * - */ - -#include - -#define rand32() ((unsigned int) rand() | ( (unsigned int) rand() << 16)) - -#if (ULONG_MAX == 4294967295UL) - #define rand_ul() rand32() - #define UL_ONEBITS 0xffffffff - #define UL_LEN 32 - #define CHECKERBOARD1 0x55555555 - #define CHECKERBOARD2 0xaaaaaaaa - #define UL_BYTE(x) ((x | x << 8 | x << 16 | x << 24)) -#elif (ULONG_MAX == 18446744073709551615ULL) - #define rand64() (((ul) rand32()) << 32 | ((ul) rand32())) - #define rand_ul() rand64() - #define UL_ONEBITS 0xffffffffffffffffUL - #define UL_LEN 64 - #define CHECKERBOARD1 0x5555555555555555 - #define CHECKERBOARD2 0xaaaaaaaaaaaaaaaa - #define UL_BYTE(x) (((ul)x | (ul)x<<8 | (ul)x<<16 | (ul)x<<24 | (ul)x<<32 | (ul)x<<40 | (ul)x<<48 | (ul)x<<56)) -#else - #error long on this platform is not 32 or 64 bits -#endif - - diff --git a/Source/MemTesterNX/source/tests.c b/Source/MemTesterNX/source/tests.c deleted file mode 100755 index 7b5f07a3..00000000 --- a/Source/MemTesterNX/source/tests.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Very simple but very effective user-space memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2020 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - * This file contains the functions for the actual tests, called from the - * main routine in memtester.c. See other comments in that file. - * - */ - -#include -#include -#include -#include -#include - -#include "tests.h" -#include "types.h" -#include "sizes.h" -#include "memtester.h" -#include - -extern unsigned short dividend; - -char progress[] = "-\\|/"; -#define PROGRESSLEN 4 -#define PROGRESSOFTEN 2000000 -#define ONE 0x00000001L - -union { - unsigned char bytes[UL_LEN/8]; - ul val; -} mword8; - -union { - unsigned short u16s[UL_LEN/16]; - ul val; -} mword16; - -/* Function definitions. */ - -int compare_regions(ulv *bufa, ulv *bufb, size_t count) { - int r = 0; - size_t i; - ulv *p1 = bufa; - ulv *p2 = bufb; - // off_t physaddr; - - for (i = 0; i < count; i++, p1++, p2++) { - if (*p1 != *p2) { - // if (use_phys) { - // physaddr = physaddrbase + (i * sizeof(ul)); - // printf("FAILURE: 0x%08lx != 0x%08lx at physical address 0x%08lx.\n", (ul) *p1, (ul) *p2, physaddr); - // } else { - // printf("FAILURE: 0x%08lx != 0x%08lx at offset 0x%08lx.\n", (ul) *p1, (ul) *p2, (ul) (i * sizeof(ul))); - // } - /* // printf("Skipping to next test..."); */ - r = -1; - } - } - return r; -} - -int test_stuck_address(ulv *bufa, size_t count) { - ulv *p1 = bufa; - unsigned int j; - size_t i; - // off_t physaddr; - - // printf(" "); - for (j = 0; j < (16 / dividend) ; j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - p1 = (ulv *) bufa; - // printf("setting %3u", j); - for (i = 0; i < count; i++) { - *p1 = ((j + i) % 2) == 0 ? (ul) p1 : ~((ul) p1); - *p1++; - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - p1 = (ulv *) bufa; - for (i = 0; i < count; i++, p1++) { - if (*p1 != (((j + i) % 2) == 0 ? (ul) p1 : ~((ul) p1))) { - // if (use_phys) { - // physaddr = physaddrbase + (i * sizeof(ul)); - // printf("FAILURE: possible bad address line at physical address 0x%08lx.\n", physaddr); - // } else { - // printf("FAILURE: possible bad address line at offset 0x%08lx.\n", (ul) (i * sizeof(ul))); - // } - // printf("Skipping to next test...\n"); - return -1; - } - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_stress_memcpy(ulv *bufa, ulv *bufb, size_t count) { - unsigned int j; - - int q = rand_ul(); - memset((void*)bufa, q, count*sizeof(ul)); - memset((void*)bufb, q, count*sizeof(ul)); - - for (j = 0; j < 128; j++) { - memcpy((void*)bufa, (void*)bufb, count*sizeof(ul)); - } - return memcmp((void*)bufa, (void*)bufb, count*sizeof(ul)); -} - -int test_stress_memset(ulv *bufa, ulv *bufb, size_t count) { - unsigned int j; - - for (j = 0; j < 128; j++) { - int q = rand_ul(); - memset((void*)bufa, q, count*sizeof(ul)); - memset((void*)bufb, q, count*sizeof(ul)); - } - return memcmp((void*)bufa, (void*)bufb, count*sizeof(ul)); -} - -int test_stress_memcmp(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - - int q = rand_ul(); - memset((void*)bufa, q, count*sizeof(ul)); - memset((void*)bufb, q, count*sizeof(ul)); - - int rc = 0; - - for (j = 0; j < 32; j++) { - // Trick compiler so that it won't skip memcmp - *p1++ = *p2++ = rand_ul(); - rc = memcmp((void*)bufa, (void*)bufb, count*sizeof(ul)); - if (rc) - return rc; - } - return rc; -} - -int test_random_value(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - // ul j = 0; - size_t i; - - // putchar(' '); - for (i = 0; i < count; i++) { - *p1++ = *p2++ = rand_ul(); - if (!(i % PROGRESSOFTEN)) { - // putchar('\b'); - // putchar(progress[++j % PROGRESSLEN]); - } - } - // printf("\b \b"); - return compare_regions(bufa, bufb, count); -} - -int test_xor_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - *p1++ ^= q; - *p2++ ^= q; - } - return compare_regions(bufa, bufb, count); -} - -int test_sub_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - *p1++ -= q; - *p2++ -= q; - } - return compare_regions(bufa, bufb, count); -} - -int test_mul_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - *p1++ *= q; - *p2++ *= q; - } - return compare_regions(bufa, bufb, count); -} - -int test_div_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - if (!q) { - q++; - } - *p1++ /= q; - *p2++ /= q; - } - return compare_regions(bufa, bufb, count); -} - -int test_or_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - *p1++ |= q; - *p2++ |= q; - } - return compare_regions(bufa, bufb, count); -} - -int test_and_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - *p1++ &= q; - *p2++ &= q; - } - return compare_regions(bufa, bufb, count); -} - -int test_seqinc_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - size_t i; - ul q = rand_ul(); - - for (i = 0; i < count; i++) { - *p1++ = *p2++ = (i + q); - } - return compare_regions(bufa, bufb, count); -} - -int test_solidbits_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - ul q; - size_t i; - - // printf(" "); - for (j = 0; j < (64 / dividend / dividend); j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - q = (j % 2) == 0 ? UL_ONEBITS : 0; - // printf("setting %3u", j); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - for (i = 0; i < count; i++) { - *p1++ = *p2++ = (i % 2) == 0 ? q : ~q; - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_checkerboard_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - ul q; - size_t i; - - // printf(" "); - for (j = 0; j < (64 / dividend / dividend); j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - q = (j % 2) == 0 ? CHECKERBOARD1 : CHECKERBOARD2; - // printf("setting %3u", j); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - for (i = 0; i < count; i++) { - *p1++ = *p2++ = (i % 2) == 0 ? q : ~q; - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_blockseq_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - size_t i; - - // printf(" "); - for (j = 0; j < (64 / dividend / dividend) ; j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - // printf("setting %3u", j); - for (i = 0; i < count; i++) { - *p1++ = *p2++ = (ul) UL_BYTE(j); - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_walkbits0_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - size_t i; - - // printf(" "); - for (j = 0; j < (UL_LEN * 2 / dividend / dividend); j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - // printf("setting %3u", j); - for (i = 0; i < count; i++) { - if (j < UL_LEN) { /* Walk it up. */ - *p1++ = *p2++ = ONE << j; - } else { /* Walk it back down. */ - *p1++ = *p2++ = ONE << (UL_LEN * 2 - j - 1); - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_walkbits1_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - size_t i; - - // printf(" "); - for (j = 0; j < (UL_LEN * 2 / dividend / dividend); j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - // printf("setting %3u", j); - for (i = 0; i < count; i++) { - if (j < UL_LEN) { /* Walk it up. */ - *p1++ = *p2++ = UL_ONEBITS ^ (ONE << j); - } else { /* Walk it back down. */ - *p1++ = *p2++ = UL_ONEBITS ^ (ONE << (UL_LEN * 2 - j - 1)); - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_bitspread_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j; - size_t i; - - // printf(" "); - for (j = 0; j < (UL_LEN * 2 / dividend / dividend); j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - // printf("setting %3u", j); - for (i = 0; i < count; i++) { - if (j < UL_LEN) { /* Walk it up. */ - *p1++ = *p2++ = (i % 2 == 0) - ? (ONE << j) | (ONE << (j + 2)) - : UL_ONEBITS ^ ((ONE << j) - | (ONE << (j + 2))); - } else { /* Walk it back down. */ - *p1++ = *p2++ = (i % 2 == 0) - ? (ONE << (UL_LEN * 2 - 1 - j)) | (ONE << (UL_LEN * 2 + 1 - j)) - : UL_ONEBITS ^ (ONE << (UL_LEN * 2 - 1 - j) - | (ONE << (UL_LEN * 2 + 1 - j))); - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -int test_bitflip_comparison(ulv *bufa, ulv *bufb, size_t count) { - ulv *p1 = bufa; - ulv *p2 = bufb; - unsigned int j, k; - ul q; - size_t i; - - // printf(" "); - for (k = 0; k < (UL_LEN / dividend / dividend); k++) { - q = ONE << k; - for (j = 0; j < 8; j++) { - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - q = ~q; - // printf("setting %3u", k * 8 + j); - p1 = (ulv *) bufa; - p2 = (ulv *) bufb; - for (i = 0; i < count; i++) { - *p1++ = *p2++ = (i % 2) == 0 ? q : ~q; - } - // printf("\b\b\b\b\b\b\b\b\b\b\b"); - // printf("testing %3u", k * 8 + j); - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - } - // printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"); - return 0; -} - -#ifdef TEST_NARROW_WRITES -int test_8bit_wide_random(ulv* bufa, ulv* bufb, size_t count) { - u8v *p1, *t; - ulv *p2; - int attempt; - unsigned int b, j = 0; - size_t i; - - // putchar(' '); - for (attempt = 0; attempt < 2; attempt++) { - if (attempt & 1) { - p1 = (u8v *) bufa; - p2 = bufb; - } else { - p1 = (u8v *) bufb; - p2 = bufa; - } - for (i = 0; i < count; i++) { - t = mword8.bytes; - *p2++ = mword8.val = rand_ul(); - for (b=0; b < UL_LEN/8; b++) { - *p1++ = *t++; - } - if (!(i % PROGRESSOFTEN)) { - // putchar('\b'); - // putchar(progress[++j % PROGRESSLEN]); - } - } - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b \b"); - return 0; -} - -int test_16bit_wide_random(ulv* bufa, ulv* bufb, size_t count) { - u16v *p1, *t; - ulv *p2; - int attempt; - unsigned int b, j = 0; - size_t i; - - // putchar( ' ' ); - for (attempt = 0; attempt < 2; attempt++) { - if (attempt & 1) { - p1 = (u16v *) bufa; - p2 = bufb; - } else { - p1 = (u16v *) bufb; - p2 = bufa; - } - for (i = 0; i < count; i++) { - t = mword16.u16s; - *p2++ = mword16.val = rand_ul(); - for (b = 0; b < UL_LEN/16; b++) { - *p1++ = *t++; - } - if (!(i % PROGRESSOFTEN)) { - // putchar('\b'); - // putchar(progress[++j % PROGRESSLEN]); - } - } - if (compare_regions(bufa, bufb, count)) { - return -1; - } - } - // printf("\b \b"); - return 0; -} -#endif diff --git a/Source/MemTesterNX/source/tests.h b/Source/MemTesterNX/source/tests.h deleted file mode 100755 index e4990abb..00000000 --- a/Source/MemTesterNX/source/tests.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Very simple yet very effective memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2020 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - * This file contains the declarations for the functions for the actual tests, - * called from the main routine in memtester.c. See other comments in that - * file. - * - */ - -/* Function declaration. */ - -int test_stuck_address(unsigned long volatile *bufa, size_t count); -int test_random_value(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_xor_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_sub_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_mul_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_div_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_or_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_and_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_seqinc_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_solidbits_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_checkerboard_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_blockseq_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_walkbits0_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_walkbits1_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_bitspread_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_bitflip_comparison(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -#ifdef TEST_NARROW_WRITES -int test_8bit_wide_random(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_16bit_wide_random(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -#endif - -int test_stress_memcpy(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_stress_memset(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); -int test_stress_memcmp(unsigned long volatile *bufa, unsigned long volatile *bufb, size_t count); \ No newline at end of file diff --git a/Source/MemTesterNX/source/types.h b/Source/MemTesterNX/source/types.h deleted file mode 100755 index 4cb41c3c..00000000 --- a/Source/MemTesterNX/source/types.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Very simple but very effective user-space memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2020 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - * This file contains typedefs, structure, and union definitions. - * - */ - -#include "sizes.h" - -typedef unsigned long ul; -typedef unsigned long long ull; -typedef unsigned long volatile ulv; -typedef unsigned char volatile u8v; -typedef unsigned short volatile u16v; - -struct test { - char *name; - int (*fp)(); -}; diff --git a/Source/TinyMemBenchNX/LICENSE.txt b/Source/Membench-NX/LICENSE.txt similarity index 100% rename from Source/TinyMemBenchNX/LICENSE.txt rename to Source/Membench-NX/LICENSE.txt diff --git a/Source/TinyMemBenchNX/Makefile b/Source/Membench-NX/Makefile similarity index 97% rename from Source/TinyMemBenchNX/Makefile rename to Source/Membench-NX/Makefile index 797dba7b..13ed6393 100644 --- a/Source/TinyMemBenchNX/Makefile +++ b/Source/Membench-NX/Makefile @@ -43,9 +43,11 @@ SOURCES := source DATA := data INCLUDES := include #ROMFS := romfs -APP_AUTHOR := hanai3Bi +APP_TITLE := Membench-NX +APP_VERSION := 1.0.0 +APP_AUTHOR := KazushiMe and Horizon-OC -TARGET_VERSION := 0.4.11 +TARGET_VERSION := 1.0.0 #--------------------------------------------------------------------------------- # options for code generation @@ -62,7 +64,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -pthread -LIBS := -lnx -lm +LIBS := -lGLESv2 -lEGL -lglapi -ldrm_nouveau -lstdc++ -lnx -lm #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/Source/Membench-NX/Membench-NX.elf b/Source/Membench-NX/Membench-NX.elf new file mode 100644 index 00000000..d2af2599 Binary files /dev/null and b/Source/Membench-NX/Membench-NX.elf differ diff --git a/Source/Membench-NX/Membench-NX.nacp b/Source/Membench-NX/Membench-NX.nacp new file mode 100644 index 00000000..40398b81 Binary files /dev/null and b/Source/Membench-NX/Membench-NX.nacp differ diff --git a/Source/Membench-NX/Membench-NX.nro b/Source/Membench-NX/Membench-NX.nro new file mode 100644 index 00000000..af694f58 Binary files /dev/null and b/Source/Membench-NX/Membench-NX.nro differ diff --git a/Source/Membench-NX/icon.jpg b/Source/Membench-NX/icon.jpg new file mode 100644 index 00000000..0cd003b7 Binary files /dev/null and b/Source/Membench-NX/icon.jpg differ diff --git a/Source/TinyMemBenchNX/readme.txt b/Source/Membench-NX/readme.txt similarity index 100% rename from Source/TinyMemBenchNX/readme.txt rename to Source/Membench-NX/readme.txt diff --git a/Source/Membench-NX/source/aarch64-asm.h b/Source/Membench-NX/source/aarch64-asm.h new file mode 100644 index 00000000..c7c9b875 --- /dev/null +++ b/Source/Membench-NX/source/aarch64-asm.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2016 Siarhei Siamashka + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __AARCH64_ASM_H__ +#define __AARCH64_ASM_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void aligned_block_read_ldp_x_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_read_ldp_q_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_copy_ldpstp_x_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_copy_ldpstp_q_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_copy_ld1st1_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); + +void aligned_block_copy_ldpstp_q_pf32_l2strm_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_copy_ldpstp_q_pf64_l2strm_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_copy_ldpstp_q_pf32_l1keep_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_copy_ldpstp_q_pf64_l1keep_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); + +void aligned_block_fill_stp_x_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_fill_stp_q_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); + +void aligned_block_fill_stnp_x_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); +void aligned_block_fill_stnp_q_aarch64(int64_t *__restrict dst, int64_t *__restrict src, int size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Source/TinyMemBenchNX/source/aarch64-asm.s b/Source/Membench-NX/source/aarch64-asm.s old mode 100755 new mode 100644 similarity index 100% rename from Source/TinyMemBenchNX/source/aarch64-asm.s rename to Source/Membench-NX/source/aarch64-asm.s diff --git a/Source/Membench-NX/source/gpu_bw.c b/Source/Membench-NX/source/gpu_bw.c new file mode 100644 index 00000000..52449e0d --- /dev/null +++ b/Source/Membench-NX/source/gpu_bw.c @@ -0,0 +1,263 @@ +/* + * gpu_bw.c - GPU bandwidth benchmark + * Mirrors FUN_71000667e0 / FUN_7100056130 from decompiled binary exactly. + */ + +#include +#include +#include +#include + +#include "gpu_bw.h" +#include +#include +#include + +static EGLDisplay s_display = EGL_NO_DISPLAY; +static EGLContext s_context = EGL_NO_CONTEXT; + +static bool egl_init(void) { + s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (s_display == EGL_NO_DISPLAY) { + printf("EGL: no display\n"); + consoleUpdate(NULL); + return false; + } + if (!eglInitialize(s_display, NULL, NULL)) { + printf("EGL: initialize failed (0x%x)\n", eglGetError()); + consoleUpdate(NULL); + return false; + } + if (!eglBindAPI(EGL_OPENGL_API)) { + printf("EGL: bindAPI(OPENGL) failed (0x%x)\n", eglGetError()); + consoleUpdate(NULL); + return false; + } + + const char *exts = eglQueryString(s_display, EGL_EXTENSIONS); + if (!exts || !strstr(exts, "EGL_KHR_surfaceless_context")) { + printf("EGL: no surfaceless_context\n"); + consoleUpdate(NULL); + return false; + } + + static const EGLint cfg_attribs[] = { + EGL_RENDERABLE_TYPE, + EGL_OPENGL_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_DEPTH_SIZE, + 24, + EGL_STENCIL_SIZE, + 8, + EGL_NONE, + }; + EGLConfig cfg; + EGLint n; + if (!eglChooseConfig(s_display, cfg_attribs, &cfg, 1, &n) || !n) { + printf("EGL: chooseConfig failed n=%d (0x%x)\n", (int)n, eglGetError()); + consoleUpdate(NULL); + return false; + } + + static const EGLint ctx_attribs[] = { + EGL_CONTEXT_MAJOR_VERSION_KHR, 4, EGL_CONTEXT_MINOR_VERSION_KHR, 3, EGL_NONE, + }; + s_context = eglCreateContext(s_display, cfg, EGL_NO_CONTEXT, ctx_attribs); + if (s_context == EGL_NO_CONTEXT) { + printf("EGL: createContext failed (0x%x)\n", eglGetError()); + consoleUpdate(NULL); + return false; + } + + if (eglMakeCurrent(s_display, EGL_NO_SURFACE, EGL_NO_SURFACE, s_context) != EGL_TRUE) { + printf("EGL: makeCurrent failed (0x%x)\n", eglGetError()); + consoleUpdate(NULL); + return false; + } + return true; +} + +static void egl_exit(void) { + eglMakeCurrent(s_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (s_context != EGL_NO_CONTEXT) { + eglDestroyContext(s_display, s_context); + s_context = EGL_NO_CONTEXT; + } + if (s_display != EGL_NO_DISPLAY) { + eglTerminate(s_display); + s_display = EGL_NO_DISPLAY; + } +} + +static GLuint compile_compute(const char *src, const char *name) { + GLuint sh = glCreateShader(GL_COMPUTE_SHADER); + glShaderSource(sh, 1, &src, NULL); + glCompileShader(sh); + GLint ok = 0; + glGetShaderiv(sh, GL_COMPILE_STATUS, &ok); + if (!ok) { + char log[256] = { 0 }; + glGetShaderInfoLog(sh, sizeof(log), NULL, log); + printf("Compute shader compile failed: %s\n", log[0] ? log : name); + glDeleteShader(sh); + return 0; + } + GLuint prog = glCreateProgram(); + glAttachShader(prog, sh); + glLinkProgram(prog); + glDeleteShader(sh); + glGetProgramiv(prog, GL_LINK_STATUS, &ok); + if (!ok) { + glDeleteProgram(prog); + return 0; + } + return prog; +} + +/* + * Mirrors FUN_7100056130: + * - one warmup dispatch + glFinish (before timing) + * - `loops` timed dispatches + glFinish + * - cntpct_el0 timing (19.2 MHz, ticks * 625/12/1e9 = seconds) + * - returns (buf_bytes * loops) / elapsed / 1e6 [MB/s] + */ +static double run_pass(GLuint prog, GLuint ssbo_src, GLuint ssbo_dst, size_t buf_bytes, int loops) { + GLuint groups = (GLuint)(buf_bytes >> 10); + + glUseProgram(prog); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo_src); + if (ssbo_dst) + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo_dst); + + glDispatchCompute(groups, 1, 1); + glFinish(); + if (glGetError() != GL_NO_ERROR) + return 0.0; + + uint64_t t0, t1; + asm volatile("mrs %0, cntpct_el0" : "=r"(t0)); + for (int i = 0; i < loops; i++) + glDispatchCompute(groups, 1, 1); + glFinish(); + asm volatile("mrs %0, cntpct_el0" : "=r"(t1)); + + if (glGetError() != GL_NO_ERROR) + return 0.0; + + double elapsed = (double)(t1 - t0) * 625.0 / 12.0 / 1000000000.0; + if (elapsed <= 0.0) + return 0.0; + return ((double)buf_bytes * (double)loops) / elapsed / 1000000.0; +} + +bool gpu_bw_run(bool is_4gb, double *copy_out, double *read_out, double *write_out) { + /* Exact GLSL sources from binary — desktop GL 4.3 */ + static const char *src_copy = "\n#version 430\n" + "layout(std430, binding = 0) buffer srcBuffer { volatile uint src[]; };\n" + "layout(std430, binding = 1) buffer dstBuffer { volatile uint dst[]; };\n" + "layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;\n" + "void main() {\n" + " dst[gl_GlobalInvocationID.x] = src[gl_GlobalInvocationID.x];\n" + "}\n"; + + static const char *src_read = "\n#version 430\n" + "layout(std430, binding = 0) buffer srcBuffer { volatile uint src[]; };\n" + "shared uint tmp;\n" + "layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;\n" + "void main() {\n" + " tmp |= src[gl_GlobalInvocationID.x];\n" + "}\n"; + + static const char *src_write = "\n#version 430\n" + "layout(std430, binding = 0) buffer srcBuffer { volatile uint src[]; };\n" + "layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;\n" + "void main() {\n" + " src[gl_GlobalInvocationID.x] = 0xAAAAAAAAu;\n" + "}\n"; + + if (!egl_init()) { + printf("Failed to initialize EGL/GL for GPU benchmark.\n"); + consoleUpdate(NULL); + return false; + } + + GLint max_ssbo = 0; + glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_ssbo); + if (max_ssbo < 1) { + printf("Failed to query GPU SSBO size.\n"); + consoleUpdate(NULL); + egl_exit(); + return false; + } + + size_t buf_bytes = (size_t)max_ssbo; + if (buf_bytes > 0x8000000) + buf_bytes = 0x8000000; + if (!is_4gb) + buf_bytes >>= 1; + buf_bytes &= ~(size_t)0x3FF; + + if (buf_bytes < 0x400) { + printf("GPU benchmark buffer is too small.\n"); + consoleUpdate(NULL); + egl_exit(); + return false; + } + + int loops = is_4gb ? 400 : 800; + int wloops = loops / 10; + + GLuint prog_copy = compile_compute(src_copy, "GPU Copy"); + GLuint prog_read = compile_compute(src_read, "GPU Read"); + GLuint prog_write = compile_compute(src_write, "GPU Write"); + if (!prog_copy || !prog_read || !prog_write) { + if (prog_copy) + glDeleteProgram(prog_copy); + if (prog_read) + glDeleteProgram(prog_read); + if (prog_write) + glDeleteProgram(prog_write); + egl_exit(); + return false; + } + + GLuint ssbo[2] = { 0, 0 }; + glGenBuffers(2, ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[0]); + glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)buf_bytes, NULL, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[1]); + glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)buf_bytes, NULL, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + if (glGetError() != GL_NO_ERROR) { + printf("Failed to allocate GPU buffers!\n"); + consoleUpdate(NULL); + glDeleteBuffers(2, ssbo); + glDeleteProgram(prog_copy); + glDeleteProgram(prog_read); + glDeleteProgram(prog_write); + egl_exit(); + return false; + } + + /* Pass order mirrors binary: warmup write+read, timed copy/read/write */ + run_pass(prog_write, ssbo[0], 0, buf_bytes, wloops); + run_pass(prog_read, ssbo[0], 0, buf_bytes, wloops); + + *copy_out = run_pass(prog_copy, ssbo[0], ssbo[1], buf_bytes, loops); + *read_out = run_pass(prog_read, ssbo[0], 0, buf_bytes, loops); + *write_out = run_pass(prog_write, ssbo[0], 0, buf_bytes, loops); + + glDeleteBuffers(2, ssbo); + glDeleteProgram(prog_copy); + glDeleteProgram(prog_read); + glDeleteProgram(prog_write); + egl_exit(); + return true; +} diff --git a/Source/Membench-NX/source/gpu_bw.h b/Source/Membench-NX/source/gpu_bw.h new file mode 100644 index 00000000..ff6b0ae5 --- /dev/null +++ b/Source/Membench-NX/source/gpu_bw.h @@ -0,0 +1,4 @@ +#pragma once +#include + +bool gpu_bw_run(bool is_4gb, double *copy_out, double *read_out, double *write_out); diff --git a/Source/Membench-NX/source/main.c b/Source/Membench-NX/source/main.c new file mode 100644 index 00000000..aa533ac4 --- /dev/null +++ b/Source/Membench-NX/source/main.c @@ -0,0 +1,422 @@ +/* + * Copyright © 2011 Siarhei Siamashka + * Copyright (c) 20xx KazushiMe + * Copyright (c) 2025 Souldbminer + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SIZE (32 * 1024 * 1024) +#ifndef MAXREPEATS + #define MAXREPEATS 10 +#endif +#ifndef LATBENCH_COUNT + #define LATBENCH_COUNT 10000000 +#endif +#define ALIGN_PADDING 0x100000 +#define CACHE_LINE_SIZE 128 + +#include + +#include "gpu_bw.h" + +#define YEL "\033[1;92m" +#define GRN "\033[1;92m" +#define RST "\033[0m" + +PadState pad; + +// Threads + +struct f_data { + void (*func)(int64_t *, int64_t *, int); + int64_t *arg1; + int64_t *arg2; + int arg3; +}; + +pthread_cond_t p_ready, p_start; +pthread_mutex_t p_lock; +pthread_t *p_worker = NULL; +struct f_data *worker_data = NULL; +int p_worker_not_ready, p_workers_ready; + +void *thread_func(void *data) { + struct f_data *d = data; + pthread_mutex_lock(&p_lock); + p_worker_not_ready--; + if (!p_worker_not_ready) + pthread_cond_signal(&p_ready); + while (p_workers_ready != 1) + pthread_cond_wait(&p_start, &p_lock); + pthread_mutex_unlock(&p_lock); + (d->func)(d->arg1, d->arg2, d->arg3); + pthread_exit(NULL); +} + +static void parallel_run(void) { + pthread_mutex_lock(&p_lock); + p_workers_ready = 1; + pthread_mutex_unlock(&p_lock); + pthread_cond_broadcast(&p_start); +} + +static void parallel_init(int threads) { + pthread_attr_t attr; + pthread_cond_init(&p_ready, NULL); + pthread_cond_init(&p_start, NULL); + pthread_mutex_init(&p_lock, NULL); + p_worker_not_ready = threads; + p_workers_ready = 0; + pthread_attr_init(&attr); + if (!p_worker || !worker_data) { + p_worker = malloc(threads * sizeof(pthread_t)); + worker_data = malloc(threads * sizeof(struct f_data)); + } + for (int i = 0; i < threads; i++) + pthread_create(p_worker + i, &attr, thread_func, worker_data + i); + pthread_mutex_lock(&p_lock); + while (p_worker_not_ready != 0) + pthread_cond_wait(&p_ready, &p_lock); + pthread_mutex_unlock(&p_lock); +} + +// memops + +void aligned_block_copy(int64_t *__restrict dst_, int64_t *__restrict src, int size) { + volatile int64_t *dst = dst_; + int64_t t1, t2, t3, t4; + while ((size -= 64) >= 0) { + t1 = *src++; + t2 = *src++; + t3 = *src++; + t4 = *src++; + *dst++ = t1; + *dst++ = t2; + *dst++ = t3; + *dst++ = t4; + t1 = *src++; + t2 = *src++; + t3 = *src++; + t4 = *src++; + *dst++ = t1; + *dst++ = t2; + *dst++ = t3; + *dst++ = t4; + } +} + +void aligned_block_fetch(int64_t *__restrict dst, int64_t *__restrict src_, int size) { + volatile int64_t *src = src_; + (void)dst; + while ((size -= 64) >= 0) { + *src++; + *src++; + *src++; + *src++; + *src++; + *src++; + *src++; + *src++; + } +} + +void aligned_block_fill(int64_t *__restrict dst_, int64_t *__restrict src, int size) { + volatile int64_t *dst = dst_; + int64_t data = *src; + while ((size -= 64) >= 0) { + *dst++ = data; + *dst++ = data; + *dst++ = data; + *dst++ = data; + *dst++ = data; + *dst++ = data; + *dst++ = data; + *dst++ = data; + } +} + +double gettime(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.; +} + +static double bandwidth_bench_helper(int threads, int64_t *dstbuf, int64_t *srcbuf, int size, void (*f)(int64_t *, int64_t *, int)) { + int i, loopcount, innerloopcount, n; + double t, t1, t2, speed, maxspeed, s, s0, s1, s2; + + s = s0 = s1 = s2 = 0.; + maxspeed = 0.; + for (n = 0; n < MAXREPEATS; n++) { + loopcount = 0; + innerloopcount = 1; + t = 0.; + do { + loopcount += innerloopcount; + for (i = 0; i < innerloopcount; i++) { + parallel_init(threads); + for (int pt = 0; pt < threads; pt++) { + (worker_data + pt)->func = f; + (worker_data + pt)->arg1 = dstbuf + size * pt / sizeof(int64_t); + (worker_data + pt)->arg2 = srcbuf + size * pt / sizeof(int64_t); + (worker_data + pt)->arg3 = size; + } + t1 = gettime(); + parallel_run(); + for (int pt = 0; pt < threads; pt++) + pthread_join(p_worker[pt], NULL); + t2 = gettime(); + t += t2 - t1; + } + innerloopcount *= 2; + } while (t < 0.5); + + speed = (double)size * threads * loopcount / t / 1000000.; + s0 += 1.; + s1 += speed; + s2 += speed * speed; + if (speed > maxspeed) + maxspeed = speed; + if (s0 > 2.) { + s = sqrt((s0 * s2 - s1 * s1) / (s0 * (s0 - 1))); + if (s < maxspeed / 1000.) + break; + } + } + return maxspeed; +} + +static char *align_up(char *ptr, int align) { + return (char *)(((uintptr_t)ptr + align - 1) & ~(uintptr_t)(align - 1)); +} + +void *alloc_nonaliased_buffers(void **buf1_, int size1, void **buf2_, int size2, void **buf3_, int size3) { + char **buf1 = (char **)buf1_, **buf2 = (char **)buf2_, **buf3 = (char **)buf3_; + int mask = (ALIGN_PADDING - 1) & ~(CACHE_LINE_SIZE - 1); + char *buf = malloc(size1 + size2 + size3 + 9 * ALIGN_PADDING); + char *ptr = buf; + memset(buf, 0xCC, size1 + size2 + size3 + 9 * ALIGN_PADDING); + ptr = align_up(ptr, ALIGN_PADDING); + if (buf1) { + *buf1 = ptr + (0xAAAAAAAA & mask); + ptr = align_up(*buf1 + size1, ALIGN_PADDING); + } + if (buf2) { + *buf2 = ptr + (0x55555555 & mask); + ptr = align_up(*buf2 + size2, ALIGN_PADDING); + } + if (buf3) { + *buf3 = ptr + (0xCCCCCCCC & mask); + } + return buf; +} + +#pragma GCC diagnostic push +static void __attribute__((noinline)) random_read_test(char *buf, int count, int nbits) { + uint32_t seed = 0; + uintptr_t mask = (1 << nbits) - 1; + uint32_t v; +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + static volatile uint32_t dummy; +#define RMA() \ + seed = seed * 1103515245 + 12345; \ + v = (seed >> 16) & 0xFF; \ + seed = seed * 1103515245 + 12345; \ + v |= (seed >> 8) & 0xFF00; \ + seed = seed * 1103515245 + 12345; \ + v |= seed & 0x7FFF0000; \ + seed |= buf[v & mask]; + while (count >= 16) { + RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() RMA() count -= 16; + } + dummy = seed; +#undef RMA +} +#pragma GCC diagnostic pop + +static double latency_measure(char *buf, int nbits, int count) { + double t_noaccess = 0, t_before, t_after, t, xs1 = 0, xs2 = 0, min_t = 0; + double xs; + int n; + + for (n = 1; n <= MAXREPEATS; n++) { + t_before = gettime(); + random_read_test(buf, count, 1); + t_after = gettime(); + if (n == 1 || t_after - t_before < t_noaccess) + t_noaccess = t_after - t_before; + } + + for (n = 1; n <= MAXREPEATS; n++) { + t_before = gettime(); + random_read_test(buf, count, nbits); + t_after = gettime(); + t = t_after - t_before - t_noaccess; + if (t < 0) + t = 0; + xs1 += t; + xs2 += t * t; + if (n == 1 || t < min_t) + min_t = t; + if (n > 2) { + xs = sqrt((xs2 * n - xs1 * xs1) / (n * (n - 1))); + if (xs < min_t / 1000.) + break; + } + } + return min_t * 1000000000.0 / count; +} + +static void latency_bench(double *l2_out, double *ram_out) { + char *buf_alloc = malloc(0x2001000); + char *buf = (char *)(((uintptr_t)buf_alloc + 4095) & ~(uintptr_t)4095); + memset(buf, 0, 0x2000000); + + /* nbits=20 (1MB) for L2, nbits=25 (32MB) for RAM — from binary assembly */ + *l2_out = latency_measure(buf, 20, LATBENCH_COUNT); + *ram_out = latency_measure(buf, 25, LATBENCH_COUNT); + + free(buf_alloc); +} + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + consoleInit(NULL); + padConfigureInput(1, HidNpadStyleSet_NpadStandard); + padInitializeDefault(&pad); + + const int threads = 3; + const int size = SIZE; + bool is_4gb = (appletGetAppletType() == AppletType_Application); + +loop: + printf("Membench-NX\n\n"); + printf("Press A to run all benchmarks.\n"); + printf("Press any other key to exit.\n\n"); + consoleUpdate(NULL); + + while (appletMainLoop()) { + padUpdate(&pad); + u64 kDown = padGetButtonsDown(&pad); + if (kDown & HidNpadButton_A) + break; + if (kDown) { + consoleExit(NULL); + return 0; + } + consoleUpdate(NULL); + } + + appletSetAutoSleepDisabled(true); + consoleClear(); + + uint32_t cpu_hz = 0, gpu_hz = 0, mem_hz = 0; + if (R_SUCCEEDED(clkrstInitialize())) { + ClkrstSession s; + clkrstOpenSession(&s, PcvModuleId_CpuBus, 3); + clkrstGetClockRate(&s, &cpu_hz); + clkrstCloseSession(&s); + clkrstOpenSession(&s, PcvModuleId_GPU, 3); + clkrstGetClockRate(&s, &gpu_hz); + clkrstCloseSession(&s); + clkrstOpenSession(&s, PcvModuleId_EMC, 3); + clkrstGetClockRate(&s, &mem_hz); + clkrstCloseSession(&s); + clkrstExit(); + } + + printf("Membench-NX\n\n"); + printf("----------------------------\n"); + printf("CPU: %.1f MHz\n", cpu_hz / 1000000.0); + printf("GPU: %.1f MHz\n", gpu_hz / 1000000.0); + printf("MEM: %.1f MHz\n", mem_hz / 1000000.0); + printf("Mode: " GRN "%s" RST "\n", is_4gb ? "Application" : "Applet"); + printf("Threads: %d (max: %d)\n", threads, threads); + printf("----------------------------\n"); + consoleUpdate(NULL); + + printf("\nStarted Bandwidth benchmark via GPU...\n"); + consoleUpdate(NULL); + + double gpu_copy = 0, gpu_read = 0, gpu_write = 0; + gpu_bw_run(is_4gb, &gpu_copy, &gpu_read, &gpu_write); + + printf(" " YEL "%-40s" RST " : %8.1f MB/s\n", "GPU Copy", gpu_copy); + printf(" " YEL "%-40s" RST " : %8.1f MB/s\n", "GPU Read", gpu_read); + printf(" " YEL "%-40s" RST " : %8.1f MB/s\n", "GPU Write", gpu_write); + consoleUpdate(NULL); + + int64_t *srcbuf, *dstbuf; + void *poolbuf = alloc_nonaliased_buffers((void **)&srcbuf, size * threads, (void **)&dstbuf, size * threads, NULL, 0); + + printf("\nStarted Bandwidth benchmark with %d threads...\n", threads); + consoleUpdate(NULL); + + double cpu_copy = bandwidth_bench_helper(threads, dstbuf, srcbuf, size, aligned_block_copy); + double cpu_read = bandwidth_bench_helper(threads, dstbuf, srcbuf, size, aligned_block_fetch); + double cpu_write = bandwidth_bench_helper(threads, dstbuf, srcbuf, size, aligned_block_fill); + + printf(" " YEL "%-40s" RST " : %8.1f MB/s\n", "CPU Copy", cpu_copy); + printf(" " YEL "%-40s" RST " : %8.1f MB/s\n", "CPU Read", cpu_read); + printf(" " YEL "%-40s" RST " : %8.1f MB/s\n", "CPU Write", cpu_write); + consoleUpdate(NULL); + + free(poolbuf); + + printf("\nStarted Latency benchmark with 1 thread...\n"); + consoleUpdate(NULL); + + double l2_ns = 0, ram_ns = 0; + latency_bench(&l2_ns, &ram_ns); + + printf(" " YEL "%-40s" RST " : %8.1f ns\n", "L2", l2_ns); + printf(" " YEL "%-40s" RST " : %8.1f ns\n", "Full RAM", ram_ns); + consoleUpdate(NULL); + + appletSetAutoSleepDisabled(false); + + printf("\nPress A to continue, any other key to exit.\n"); + consoleUpdate(NULL); + + while (appletMainLoop()) { + padUpdate(&pad); + u64 kDown = padGetButtonsDown(&pad); + if (kDown & HidNpadButton_A) { + consoleClear(); + goto loop; + } + if (kDown) + break; + consoleUpdate(NULL); + } + + consoleExit(NULL); + return 0; +} diff --git a/Source/TinyMemBenchNX/.gitignore b/Source/TinyMemBenchNX/.gitignore deleted file mode 100644 index 3044e05c..00000000 --- a/Source/TinyMemBenchNX/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.DS_Store -build/ -*.elf -*.nacp -*.nro \ No newline at end of file diff --git a/Source/TinyMemBenchNX/source/aarch64-asm.h b/Source/TinyMemBenchNX/source/aarch64-asm.h deleted file mode 100644 index 8681abc2..00000000 --- a/Source/TinyMemBenchNX/source/aarch64-asm.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright © 2016 Siarhei Siamashka - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef __AARCH64_ASM_H__ -#define __AARCH64_ASM_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void aligned_block_read_ldp_x_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_read_ldp_q_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_copy_ldpstp_x_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_copy_ldpstp_q_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_copy_ld1st1_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); - -void aligned_block_copy_ldpstp_q_pf32_l2strm_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_copy_ldpstp_q_pf64_l2strm_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_copy_ldpstp_q_pf32_l1keep_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_copy_ldpstp_q_pf64_l1keep_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); - -void aligned_block_fill_stp_x_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_fill_stp_q_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); - -void aligned_block_fill_stnp_x_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); -void aligned_block_fill_stnp_q_aarch64(int64_t * __restrict dst, - int64_t * __restrict src, - int size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Source/TinyMemBenchNX/source/main.c b/Source/TinyMemBenchNX/source/main.c deleted file mode 100644 index f7fe42db..00000000 --- a/Source/TinyMemBenchNX/source/main.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* - * Copyright © 2011 Siarhei Siamashka - * - * Copyright (c) 20xx KazushiMe - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * pthread fork by sun409 (https://github.com/sun409/tinymembench-pthread) - * - * Switch port by Kazushi and built with libnx. - */ - -// Include the most common headers from the C standard library -#include -#include -#include -#include -#include -#include -#include - -// Multi-thread support -#include -#include -#include - -#define __ASM_OPT_H__ -#define SIZE (32 * 1024 * 1024) -#define BLOCKSIZE 2048 -#ifndef MAXREPEATS -# define MAXREPEATS 10 -#endif -#ifndef LATBENCH_COUNT -# define LATBENCH_COUNT 10000000 -#endif - -#define ALIGN_PADDING 0x100000 -#define CACHE_LINE_SIZE 128 - -#include "aarch64-asm.h" -#include - -PadState pad; - -struct f_data -{ - void (*func)(int64_t *, int64_t *, int); - int64_t *arg1; - int64_t *arg2; - int arg3; -}; - -pthread_cond_t p_ready, p_start; -pthread_mutex_t p_lock; -pthread_t *p_worker = NULL; -struct f_data *worker_data = NULL; -int p_worker_not_ready, p_workers_ready; - -void *thread_func(void *data) -{ - struct f_data *data_ptr = data; - - pthread_mutex_lock(&p_lock); - p_worker_not_ready--; - - if (!p_worker_not_ready) - pthread_cond_signal(&p_ready); - - while (p_workers_ready != 1) - pthread_cond_wait(&p_start, &p_lock); - - pthread_mutex_unlock(&p_lock); - - (data_ptr->func)(data_ptr->arg1, data_ptr->arg2, data_ptr->arg3); - - pthread_exit(NULL); -} - -static void parallel_run(void) -{ - pthread_mutex_lock(&p_lock); - p_workers_ready = 1; - pthread_mutex_unlock(&p_lock); - pthread_cond_broadcast(&p_start); -} - -static void parallel_init(int threads) -{ - pthread_attr_t attr; - - pthread_cond_init(&p_ready, NULL); - pthread_cond_init(&p_start, NULL); - pthread_mutex_init(&p_lock, NULL); - p_worker_not_ready = threads; - p_workers_ready = 0; - pthread_attr_init(&attr); - - if (!p_worker || !worker_data) - { - p_worker = (pthread_t *)malloc(threads * sizeof(pthread_t)); - worker_data = (struct f_data *)malloc(threads * sizeof(struct f_data)); - } - - for (int i = 0; i < threads; i++) - { - pthread_create(p_worker + i, &attr, thread_func, worker_data + i); - } - - pthread_mutex_lock(&p_lock); - while (p_worker_not_ready != 0) - pthread_cond_wait(&p_ready, &p_lock); - - pthread_mutex_unlock(&p_lock); -} - -typedef struct -{ - const char *description; - int use_tmpbuf; - void (*f)(int64_t *, int64_t *, int); -} bench_info; - -static char *align_up(char *ptr, int align) -{ - return (char *)(((uintptr_t)ptr + align - 1) & ~(uintptr_t)(align - 1)); -} - -void aligned_block_copy(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t t1, t2, t3, t4; - while ((size -= 64) >= 0) - { - t1 = *src++; - t2 = *src++; - t3 = *src++; - t4 = *src++; - *dst++ = t1; - *dst++ = t2; - *dst++ = t3; - *dst++ = t4; - t1 = *src++; - t2 = *src++; - t3 = *src++; - t4 = *src++; - *dst++ = t1; - *dst++ = t2; - *dst++ = t3; - *dst++ = t4; - } -} - -void aligned_block_copy_backwards(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t t1, t2, t3, t4; - src += size / 8 - 1; - dst += size / 8 - 1; - while ((size -= 64) >= 0) - { - t1 = *src--; - t2 = *src--; - t3 = *src--; - t4 = *src--; - *dst-- = t1; - *dst-- = t2; - *dst-- = t3; - *dst-- = t4; - t1 = *src--; - t2 = *src--; - t3 = *src--; - t4 = *src--; - *dst-- = t1; - *dst-- = t2; - *dst-- = t3; - *dst-- = t4; - } -} - -void aligned_block_copy_backwards_bs32(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t t1, t2, t3, t4; - src += size / 8 - 8; - dst += size / 8 - 8; - while ((size -= 64) >= 0) - { - t1 = src[4]; - t2 = src[5]; - t3 = src[6]; - t4 = src[7]; - dst[4] = t1; - dst[5] = t2; - dst[6] = t3; - dst[7] = t4; - t1 = src[0]; - t2 = src[1]; - t3 = src[2]; - t4 = src[3]; - dst[0] = t1; - dst[1] = t2; - dst[2] = t3; - dst[3] = t4; - src -= 8; - dst -= 8; - } -} - -void aligned_block_copy_backwards_bs64(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t t1, t2, t3, t4; - src += size / 8 - 8; - dst += size / 8 - 8; - while ((size -= 64) >= 0) - { - t1 = src[0]; - t2 = src[1]; - t3 = src[2]; - t4 = src[3]; - dst[0] = t1; - dst[1] = t2; - dst[2] = t3; - dst[3] = t4; - t1 = src[4]; - t2 = src[5]; - t3 = src[6]; - t4 = src[7]; - dst[4] = t1; - dst[5] = t2; - dst[6] = t3; - dst[7] = t4; - src -= 8; - dst -= 8; - } -} - -void aligned_block_copy_pf32(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t t1, t2, t3, t4; - while ((size -= 64) >= 0) - { - __builtin_prefetch(src + 32, 0, 0); - t1 = *src++; - t2 = *src++; - t3 = *src++; - t4 = *src++; - *dst++ = t1; - *dst++ = t2; - *dst++ = t3; - *dst++ = t4; - __builtin_prefetch(src + 32, 0, 0); - t1 = *src++; - t2 = *src++; - t3 = *src++; - t4 = *src++; - *dst++ = t1; - *dst++ = t2; - *dst++ = t3; - *dst++ = t4; - } -} - -void aligned_block_copy_pf64(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t t1, t2, t3, t4; - while ((size -= 64) >= 0) - { - __builtin_prefetch(src + 32, 0, 0); - t1 = *src++; - t2 = *src++; - t3 = *src++; - t4 = *src++; - *dst++ = t1; - *dst++ = t2; - *dst++ = t3; - *dst++ = t4; - t1 = *src++; - t2 = *src++; - t3 = *src++; - t4 = *src++; - *dst++ = t1; - *dst++ = t2; - *dst++ = t3; - *dst++ = t4; - } -} - -void aligned_block_fetch(int64_t * __restrict dst, - int64_t * __restrict src_, - int size) -{ - volatile int64_t *src = src_; - while ((size -= 64) >= 0) - { - *src++; - *src++; - *src++; - *src++; - *src++; - *src++; - *src++; - *src++; - } -} - -void aligned_block_fill(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t data = *src; - while ((size -= 64) >= 0) - { - *dst++ = data; - *dst++ = data; - *dst++ = data; - *dst++ = data; - *dst++ = data; - *dst++ = data; - *dst++ = data; - *dst++ = data; - } -} - -void aligned_block_fill_shuffle16(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t data = *src; - while ((size -= 64) >= 0) - { - dst[0 + 0] = data; - dst[1 + 0] = data; - dst[1 + 2] = data; - dst[0 + 2] = data; - dst[1 + 4] = data; - dst[0 + 4] = data; - dst[0 + 6] = data; - dst[1 + 6] = data; - dst += 8; - } -} - -void aligned_block_fill_shuffle32(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t data = *src; - while ((size -= 64) >= 0) - { - dst[3 + 0] = data; - dst[0 + 0] = data; - dst[2 + 0] = data; - dst[1 + 0] = data; - dst[3 + 4] = data; - dst[0 + 4] = data; - dst[2 + 4] = data; - dst[1 + 4] = data; - dst += 8; - } -} - -void aligned_block_fill_shuffle64(int64_t * __restrict dst_, - int64_t * __restrict src, - int size) -{ - volatile int64_t *dst = dst_; - int64_t data = *src; - while ((size -= 64) >= 0) - { - dst[5] = data; - dst[2] = data; - dst[7] = data; - dst[6] = data; - dst[1] = data; - dst[3] = data; - dst[0] = data; - dst[4] = data; - dst += 8; - } -} - -double gettime(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.; -} - -static double bandwidth_bench_helper(int threads, - int64_t *dstbuf, int64_t *srcbuf, - int64_t *tmpbuf, - int size, int blocksize, - const char *indent_prefix, - int use_tmpbuf, - void (*f)(int64_t *, int64_t *, int), - const char *description) -{ - int i, j, loopcount, innerloopcount, n; - double t, t1, t2; - double speed, maxspeed; - double s, s0, s1, s2; - - /* do up to MAXREPEATS measurements */ - s = s0 = s1 = s2 = 0.; - maxspeed = 0.; - for (n = 0; n < MAXREPEATS; n++) - { - parallel_init(threads); - for (int pt = 0; pt < threads; pt++) - { - (worker_data + pt)->func = f; - (worker_data + pt)->arg1 = dstbuf + size * pt / sizeof(int64_t); - (worker_data + pt)->arg2 = srcbuf + size * pt / sizeof(int64_t); - (worker_data + pt)->arg3 = size; - } - parallel_run(); - for (int pt = 0; pt < threads; pt++) - pthread_join(p_worker[pt], NULL); - - loopcount = 0; - innerloopcount = 1; - t = 0.; - do - { - loopcount += innerloopcount; - if (use_tmpbuf) - { - for (i = 0; i < innerloopcount; i++) - { - t1 = gettime(); - for (j = 0; j < size; j += blocksize) - { - f(tmpbuf, srcbuf + j / sizeof(int64_t), blocksize); - f(dstbuf + j / sizeof(int64_t), tmpbuf, blocksize); - } - t2 = gettime(); - t += t2 - t1; - } - } - else - { - for (i = 0; i < innerloopcount; i++) - { - parallel_init(threads); - for (int pt = 0; pt < threads; ++pt) - { - (worker_data + pt)->func = f; - (worker_data + pt)->arg1 = dstbuf + size * pt / sizeof(int64_t); - (worker_data + pt)->arg2 = srcbuf + size * pt / sizeof(int64_t); - (worker_data + pt)->arg3 = size; - } - - t1 = gettime(); - parallel_run(); - for (int pt = 0; pt < threads; ++pt) - pthread_join(p_worker[pt], NULL); - t2 = gettime(); - t += t2 - t1; - } - } - innerloopcount *= 2; - } while (t < 0.5); - speed = (double)size * (use_tmpbuf ? 1 : threads) * loopcount / t / 1000000.; - - s0 += 1.; - s1 += speed; - s2 += speed * speed; - - if (speed > maxspeed) - maxspeed = speed; - - if (s0 > 2.) - { - s = sqrt((s0 * s2 - s1 * s1) / (s0 * (s0 - 1))); - if (s < maxspeed / 1000.) - break; - } - } - - if (maxspeed > 0 && s / maxspeed * 100. >= 0.1) - { - printf("%s%-40s : %8.1f MB/s (%.1f%%)\n", indent_prefix, description, - maxspeed, s / maxspeed * 100.); - } - else - { - printf("%s%-40s : %8.1f MB/s\n", indent_prefix, description, maxspeed); - } - - consoleUpdate(NULL); - return maxspeed; -} - -void bandwidth_bench(int threads, - int64_t *dstbuf, int64_t *srcbuf, int64_t *tmpbuf, - int size, int blocksize, const char *indent_prefix, - bench_info *bi) -{ - while (bi->f) - { - bandwidth_bench_helper(threads, - dstbuf, srcbuf, tmpbuf, size, blocksize, - indent_prefix, bi->use_tmpbuf, - bi->f, - bi->description); - bi++; - } -} - -void memcpy_wrapper(int64_t *dst, int64_t *src, int size) -{ - memcpy(dst, src, size); -} - -void memset_wrapper(int64_t *dst, int64_t *src, int size) -{ - memset(dst, src[0], size); -} - -static bench_info aarch64_neon[] = -{ - { "NEON LDP (READ)", 0, aligned_block_read_ldp_q_aarch64 }, - { "NEON LDP/STP copy (COPY)", 0, aligned_block_copy_ldpstp_q_aarch64 }, - { "NEON LDP/STP copy pldl2strm (32B step)", 0, aligned_block_copy_ldpstp_q_pf32_l2strm_aarch64 }, - { "NEON LDP/STP copy pldl2strm (64B step)", 0, aligned_block_copy_ldpstp_q_pf64_l2strm_aarch64 }, - { "NEON LDP/STP copy pldl1keep (32B step)", 0, aligned_block_copy_ldpstp_q_pf32_l1keep_aarch64 }, - { "NEON LDP/STP copy pldl1keep (64B step)", 0, aligned_block_copy_ldpstp_q_pf64_l1keep_aarch64 }, - { "NEON LD1/ST1 copy", 0, aligned_block_copy_ld1st1_aarch64 }, - { "NEON STP fill (WRITE)", 0, aligned_block_fill_stp_q_aarch64 }, - { "NEON STNP fill", 0, aligned_block_fill_stnp_q_aarch64 }, - { "ARM LDP", 0, aligned_block_read_ldp_x_aarch64 }, - { "ARM LDP/STP copy", 0, aligned_block_copy_ldpstp_x_aarch64 }, - { "ARM STP fill", 0, aligned_block_fill_stp_x_aarch64 }, - { "ARM STNP fill", 0, aligned_block_fill_stnp_x_aarch64 }, - { NULL, 0, NULL } -}; - -bench_info *get_asm_benchmarks(void) -{ - return aarch64_neon; -} - -static bench_info c_benchmarks[] = -{ - { "C copy backwards", 0, aligned_block_copy_backwards }, - { "C copy backwards (32B blocks)", 0, aligned_block_copy_backwards_bs32 }, - { "C copy backwards (64B blocks)", 0, aligned_block_copy_backwards_bs64 }, - { "C copy", 0, aligned_block_copy }, - { "C copy prefetched (32B step)", 0, aligned_block_copy_pf32 }, - { "C copy prefetched (64B step)", 0, aligned_block_copy_pf64 }, - // { "C 2-pass copy", 1, aligned_block_copy }, - // { "C 2-pass copy prefetched (32B step)", 1, aligned_block_copy_pf32 }, - // { "C 2-pass copy prefetched (64B step)", 1, aligned_block_copy_pf64 }, - { "C fetch", 0, aligned_block_fetch }, - { "C fill", 0, aligned_block_fill }, - { "C fill (shuffle within 16B blocks)", 0, aligned_block_fill_shuffle16 }, - { "C fill (shuffle within 32B blocks)", 0, aligned_block_fill_shuffle32 }, - { "C fill (shuffle within 64B blocks)", 0, aligned_block_fill_shuffle64 }, - { NULL, 0, NULL } -}; - -static bench_info libc_benchmarks[] = -{ - { "standard memcpy", 0, memcpy_wrapper }, - { "standard memset", 0, memset_wrapper }, - { NULL, 0, NULL } -}; - -void *alloc_four_nonaliased_buffers(void **buf1_, int size1, - void **buf2_, int size2, - void **buf3_, int size3, - void **buf4_, int size4) -{ - char **buf1 = (char **)buf1_, **buf2 = (char **)buf2_; - char **buf3 = (char **)buf3_, **buf4 = (char **)buf4_; - int antialias_pattern_mask = (ALIGN_PADDING - 1) & ~(CACHE_LINE_SIZE - 1); - char *buf, *ptr; - - if (!buf1 || size1 < 0) - size1 = 0; - if (!buf2 || size2 < 0) - size2 = 0; - if (!buf3 || size3 < 0) - size3 = 0; - if (!buf4 || size4 < 0) - size4 = 0; - - ptr = buf = - (char *)malloc(size1 + size2 + size3 + size4 + 9 * ALIGN_PADDING); - memset(buf, 0xCC, size1 + size2 + size3 + size4 + 9 * ALIGN_PADDING); - - ptr = align_up(ptr, ALIGN_PADDING); - if (buf1) - { - *buf1 = ptr + (0xAAAAAAAA & antialias_pattern_mask); - ptr = align_up(*buf1 + size1, ALIGN_PADDING); - } - if (buf2) - { - *buf2 = ptr + (0x55555555 & antialias_pattern_mask); - ptr = align_up(*buf2 + size2, ALIGN_PADDING); - } - if (buf3) - { - *buf3 = ptr + (0xCCCCCCCC & antialias_pattern_mask); - ptr = align_up(*buf3 + size3, ALIGN_PADDING); - } - if (buf4) - { - *buf4 = ptr + (0x33333333 & antialias_pattern_mask); - } - - return buf; -} - -#pragma GCC diagnostic push -static void __attribute__((noinline)) random_read_test(char *zerobuffer, - int count, int nbits) -{ - uint32_t seed = 0; - uintptr_t addrmask = (1 << nbits) - 1; - uint32_t v; - - #pragma GCC diagnostic ignored "-Wunused-but-set-variable" - static volatile uint32_t dummy; - - #define RANDOM_MEM_ACCESS() \ - seed = seed * 1103515245 + 12345; \ - v = (seed >> 16) & 0xFF; \ - seed = seed * 1103515245 + 12345; \ - v |= (seed >> 8) & 0xFF00; \ - seed = seed * 1103515245 + 12345; \ - v |= seed & 0x7FFF0000; \ - seed |= zerobuffer[v & addrmask]; - - while (count >= 16) { - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - count -= 16; - } - dummy = seed; - #undef RANDOM_MEM_ACCESS -} - -static void __attribute__((noinline)) random_dual_read_test(char *zerobuffer, - int count, int nbits) -{ - uint32_t seed = 0; - uintptr_t addrmask = (1 << nbits) - 1; - uint32_t v1, v2; - - #pragma GCC diagnostic ignored "-Wunused-but-set-variable" - static volatile uint32_t dummy; - - #define RANDOM_MEM_ACCESS() \ - seed = seed * 1103515245 + 12345; \ - v1 = (seed >> 8) & 0xFF00; \ - seed = seed * 1103515245 + 12345; \ - v2 = (seed >> 8) & 0xFF00; \ - seed = seed * 1103515245 + 12345; \ - v1 |= seed & 0x7FFF0000; \ - seed = seed * 1103515245 + 12345; \ - v2 |= seed & 0x7FFF0000; \ - seed = seed * 1103515245 + 12345; \ - v1 |= (seed >> 16) & 0xFF; \ - v2 |= (seed >> 24); \ - v2 &= addrmask; \ - v1 ^= v2; \ - seed |= zerobuffer[v2]; \ - seed += zerobuffer[v1 & addrmask]; - - while (count >= 16) { - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - RANDOM_MEM_ACCESS(); - count -= 16; - } - dummy = seed; - #undef RANDOM_MEM_ACCESS -} -#pragma GCC diagnostic pop - -static uint32_t rand32() -{ - static int seed = 0; - uint32_t hi, lo; - hi = (seed = seed * 1103515245 + 12345) >> 16; - lo = (seed = seed * 1103515245 + 12345) >> 16; - return (hi << 16) + lo; -} - -int latency_bench(int size, int count, int use_hugepage, int quick) -{ - double t, t2, t_before, t_after, t_noaccess, t_noaccess2 = 0; - double xs, xs1, xs2; - double ys, ys1, ys2; - double min_t, min_t2; - int nbits, n; - char *buffer, *buffer_alloc; -#if !defined(__linux__) || !defined(MADV_HUGEPAGE) - if (use_hugepage) - return 0; - buffer_alloc = (char *)malloc(size + 4095); - if (!buffer_alloc) - return 0; - buffer = (char *)(((uintptr_t)buffer_alloc + 4095) & ~(uintptr_t)4095); -#else - if (posix_memalign((void **)&buffer_alloc, 4 * 1024 * 1024, size) != 0) - return 0; - buffer = buffer_alloc; - if (use_hugepage && madvise(buffer, size, use_hugepage > 0 ? - MADV_HUGEPAGE : MADV_NOHUGEPAGE) != 0) - { - free(buffer_alloc); - return 0; - } -#endif - memset(buffer, 0, size); - - for (n = 1; n <= MAXREPEATS; n++) - { - t_before = gettime(); - random_read_test(buffer, count, 1); - t_after = gettime(); - if (n == 1 || t_after - t_before < t_noaccess) - t_noaccess = t_after - t_before; - - t_before = gettime(); - random_dual_read_test(buffer, count, 1); - t_after = gettime(); - if (n == 1 || t_after - t_before < t_noaccess2) - t_noaccess2 = t_after - t_before; - } - - printf("\nblock size : single random read / dual random read"); - if (use_hugepage > 0) - printf(", [MADV_HUGEPAGE]\n"); - else if (use_hugepage < 0) - printf(", [MADV_NOHUGEPAGE]\n"); - else - printf("\n"); - - consoleUpdate(NULL); - - int start = quick ? 20 : 10; - for (nbits = start; (1 << nbits) <= size; nbits++) - { - int testsize = 1 << nbits; - xs1 = xs2 = ys = ys1 = ys2 = 0; - for (n = 1; n <= MAXREPEATS; n++) - { - int testoffs = (rand32() % (size / testsize)) * testsize; - - t_before = gettime(); - random_read_test(buffer + testoffs, count, nbits); - t_after = gettime(); - t = t_after - t_before - t_noaccess; - if (t < 0) t = 0; - - xs1 += t; - xs2 += t * t; - - if (n == 1 || t < min_t) - min_t = t; - - t_before = gettime(); - random_dual_read_test(buffer + testoffs, count, nbits); - t_after = gettime(); - t2 = t_after - t_before - t_noaccess2; - if (t2 < 0) t2 = 0; - - ys1 += t2; - ys2 += t2 * t2; - - if (n == 1 || t2 < min_t2) - min_t2 = t2; - - if (n > 2) - { - xs = sqrt((xs2 * n - xs1 * xs1) / (n * (n - 1))); - ys = sqrt((ys2 * n - ys1 * ys1) / (n * (n - 1))); - if (xs < min_t / 1000. && ys < min_t2 / 1000.) - break; - } - } - printf("%10d : %6.1f ns / %6.1f ns \n", (1 << nbits), - min_t * 1000000000. / count, min_t2 * 1000000000. / count); - - consoleUpdate(NULL); - } - free(buffer_alloc); - return 1; -} - -void waitForKeyA() { - while (appletMainLoop()) - { - padUpdate(&pad); - - u64 kDown = padGetButtonsDown(&pad); - - if (kDown & HidNpadButton_A) - break; - else if(kDown) - { - consoleExit(NULL); - exit(0); - } - - consoleUpdate(NULL); - } -} - -void printClock() -{ - int res = 0; - uint32_t cpu_hz = 0, mem_hz = 0; - - ClkrstSession clkrstSession; - res = clkrstInitialize(); - if(R_FAILED(res)) { - fatalThrow(res); - } - - clkrstOpenSession(&clkrstSession, PcvModuleId_CpuBus, 3); - clkrstGetClockRate(&clkrstSession, &cpu_hz); - clkrstCloseSession(&clkrstSession); - clkrstOpenSession(&clkrstSession, PcvModuleId_EMC, 3); - clkrstGetClockRate(&clkrstSession, &mem_hz); - clkrstCloseSession(&clkrstSession); - clkrstExit(); - - printf("== CPU: %u.%u MHz ==\n== MEM: %u.%u MHz ==\n", - cpu_hz/1000000, cpu_hz/100000 - cpu_hz/1000000*10, - mem_hz/1000000, mem_hz/100000 - mem_hz/1000000*10); - consoleUpdate(NULL); -} - -// Main program entrypoint -int main(int argc, char* argv[]) -{ - consoleInit(NULL); - - printf("TinyMemBenchNX v0.4.11\n\ -(based on tinymembench-pthread, a multi-thread fork of simple benchmark for memory throughput and latency)\n\n"); - printf("Copyright (c) 2011-2016 Siarhei Siamashka\n"); - printf("Copyright (c) 2023 KazushiMe\n"); - printf("Copyright (c) 2023 hanai3Bi\n"); - printf("Copyright (c) 2025 Souldbminer\n"); - - printf("\n"); - consoleUpdate(NULL); - - padConfigureInput(1, HidNpadStyleSet_NpadStandard); - - padInitializeDefault(&pad); - - int64_t *srcbuf, *dstbuf, *tmpbuf; - void *poolbuf; - size_t bufsize = SIZE; - int threads = 0; - -loop: - printf("!!! Memory bandwidth heavily depends on CPU clock. !!!\n\n"); - printf("\ -Press A to start quick test.\n\ -Press X to start bandwidth test.\n\ -Press Y to start latency test.\n\ -Press any other key to exit.\n\n"); - consoleUpdate(NULL); - - while (appletMainLoop()) - { - padUpdate(&pad); - - u64 kDown = padGetButtonsDown(&pad); - - if (kDown & HidNpadButton_A) - { - threads = 3; - goto quick; - break; - } - else if (kDown & HidNpadButton_X) - { - threads = 3; - goto bandwidth; - break; - } - else if (kDown & HidNpadButton_Y) - { - threads = 3; - goto latency; - break; - } - else if (kDown) - { - consoleExit(NULL); - exit(0); - } - } - -quick: - - poolbuf = alloc_four_nonaliased_buffers((void **)&srcbuf, bufsize * threads, - (void **)&dstbuf, bufsize * threads, - (void **)&tmpbuf, BLOCKSIZE * threads, - NULL, 0); - - printClock(); - printf("== Thread: %d ==\n", threads); - consoleUpdate(NULL); - - bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE/2, " ", libc_benchmarks); - - free(poolbuf); - - int latbench_size = SIZE * 2, latbench_count = LATBENCH_COUNT; - - if (!latency_bench(latbench_size, latbench_count, -1, 1) || - !latency_bench(latbench_size, latbench_count, 1, 1)) - { - latency_bench(latbench_size, latbench_count, 0, 1); - } - - printf("\nPress A to continue, any other key to exit.\n\n"); - waitForKeyA(); - consoleClear(); - goto loop; - -bandwidth: - - printf("==========================================================================\n"); - printf("== Memory bandwidth tests ==\n"); - printf("== ==\n"); - printf("== Note 1: 1MB = 1000000 bytes ==\n"); - printf("== Note 2: Results for 'copy' tests show how many bytes can be ==\n"); - printf("== copied per second (adding together read and writen ==\n"); - printf("== bytes would have provided twice higher numbers) ==\n"); - printf("== Note 3: 2-pass copy means that we are using a small temporary buffer ==\n"); - printf("== to first fetch data into it, and only then write it to the ==\n"); - printf("== destination (source -> L1 cache, L1 cache -> destination) ==\n"); - printf("== Note 4: If sample standard deviation exceeds 0.1%%, it is shown in ==\n"); - printf("== brackets ==\n"); - printf("==========================================================================\n\n"); - - poolbuf = alloc_four_nonaliased_buffers((void **)&srcbuf, bufsize * threads, - (void **)&dstbuf, bufsize * threads, - (void **)&tmpbuf, BLOCKSIZE * threads, - NULL, 0); - - printClock(); - printf("== Thread: %d ==\n", threads); - consoleUpdate(NULL); - - bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", c_benchmarks); - printf(" ---\n"); - - bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", libc_benchmarks); - bench_info *bi = get_asm_benchmarks(); - if (bi->f) { - printf(" ---\n"); - bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", bi); - } - - free(poolbuf); - - printf("\nPress A to continue, any other key to exit.\n\n"); - waitForKeyA(); - consoleClear(); - goto loop; - -latency: - - latbench_size = SIZE * 2, latbench_count = LATBENCH_COUNT; - - printf("\n"); - printf("==========================================================================\n"); - printf("== Memory latency test ==\n"); - printf("== ==\n"); - printf("== Average time is measured for random memory accesses in the buffers ==\n"); - printf("== of different sizes. The larger is the buffer, the more significant ==\n"); - printf("== are relative contributions of TLB, L1/L2 cache misses and SDRAM ==\n"); - printf("== accesses. For extremely large buffer sizes we are expecting to see ==\n"); - printf("== page table walk with several requests to SDRAM for almost every ==\n"); - printf("== memory access (though 64MiB is not nearly large enough to experience ==\n"); - printf("== this effect to its fullest). ==\n"); - printf("== ==\n"); - printf("== Note 1: All the numbers are representing extra time, which needs to ==\n"); - printf("== be added to L1 cache latency. The cycle timings for L1 cache ==\n"); - printf("== latency can be usually found in the processor documentation. ==\n"); - printf("== Note 2: Dual random read means that we are simultaneously performing ==\n"); - printf("== two independent memory accesses at a time. In the case if ==\n"); - printf("== the memory subsystem can't handle multiple outstanding ==\n"); - printf("== requests, dual random read has the same timings as two ==\n"); - printf("== single reads performed one after another. ==\n"); - printf("==========================================================================\n\n"); - - consoleUpdate(NULL); - printClock(); - - if (!latency_bench(latbench_size, latbench_count, -1, 0) || - !latency_bench(latbench_size, latbench_count, 1, 0)) - { - latency_bench(latbench_size, latbench_count, 0, 0); - } - - printf("\nPress A to continue, any other key to exit.\n\n"); - waitForKeyA(); - consoleClear(); - goto loop; - - // Deinitialize and clean up resources used by the console (important!) - consoleExit(NULL); - return 0; -}