diff --git a/.gitignore b/.gitignore index 154cd292..3f5bb546 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,10 @@ cortex.log api.log prism.log api.json -openai-python/* \ No newline at end of file +openai-python/* +build +cortex-js/cortex.exe +cortex-js/package-lock.json +.vscode +cortex-js/command +cortex-js/src/infrastructure/commanders/test/test_data diff --git a/cortex-js/cpuinfo/bin/cpuinfo b/cortex-js/cpuinfo/bin/cpuinfo deleted file mode 100644 index a4e172c3..00000000 Binary files a/cortex-js/cpuinfo/bin/cpuinfo and /dev/null differ diff --git a/cortex-js/cpuinfo/bin/cpuinfo.exe b/cortex-js/cpuinfo/bin/cpuinfo.exe deleted file mode 100644 index c96c8192..00000000 Binary files a/cortex-js/cpuinfo/bin/cpuinfo.exe and /dev/null differ diff --git a/cortex-js/cpuinfo/binding.gyp b/cortex-js/cpuinfo/binding.gyp new file mode 100644 index 00000000..652246b5 --- /dev/null +++ b/cortex-js/cpuinfo/binding.gyp @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "target_name": "cpuinfo", + "sources": ["src/cpuinfo.cpp"], + "include_dirs": [ " InstructionSet[]; +}; diff --git a/cortex-js/cpuinfo/package.json b/cortex-js/cpuinfo/package.json new file mode 100644 index 00000000..447324e5 --- /dev/null +++ b/cortex-js/cpuinfo/package.json @@ -0,0 +1,33 @@ +{ + "name": "cpuinfo", + "version": "1.0.0", + "description": "Get CPU instructions", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "test": "ts-node index.ts", + "install": "prebuild-install -r napi || node-gyp rebuild" + }, + "author": "", + "license": "ISC", + "gypfile": true, + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1" + }, + "devDependencies": { + "@types/node": "^20.14.9", + "typescript": "^5.5.3" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "files": [ + "binding.gyp", + "deps/", + "*.js", + "*.d.ts", + "src/" + ] +} diff --git a/cortex-js/cpuinfo/src/cpuinfo.cpp b/cortex-js/cpuinfo/src/cpuinfo.cpp index 9ba181ca..b0b947c1 100644 --- a/cortex-js/cpuinfo/src/cpuinfo.cpp +++ b/cortex-js/cpuinfo/src/cpuinfo.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,85 +6,88 @@ #ifdef _WIN32 #include #include -typedef unsigned __int32 uint32_t; +typedef unsigned __int32 uint32_t; #else #include #endif using namespace std; +#if defined(_WIN32) || defined(LINUX) #define MAX_INTEL_TOP_LVL 4 -class CPUID { +class CPUID +{ uint32_t regs[4]; - public: - explicit CPUID(unsigned funcId, unsigned subFuncId) { +public: + explicit CPUID(unsigned funcId, unsigned subFuncId) + { #ifdef _WIN32 __cpuidex((int *)regs, (int)funcId, (int)subFuncId); #else - asm volatile - ("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) - : "a" (funcId), "c" (subFuncId)); + asm volatile("cpuid" : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(funcId), "c"(subFuncId)); // ECX is set to zero for CPUID function 4 #endif } - const uint32_t &EAX() const {return regs[0];} - const uint32_t &EBX() const {return regs[1];} - const uint32_t &ECX() const {return regs[2];} - const uint32_t &EDX() const {return regs[3];} + const uint32_t &EAX() const { return regs[0]; } + const uint32_t &EBX() const { return regs[1]; } + const uint32_t &ECX() const { return regs[2]; } + const uint32_t &EDX() const { return regs[3]; } }; -class CPUInfo { - public: - CPUInfo(); - string vendor() const { return mVendorId; } - string model() const { return mModelName; } - int cores() const { return mNumCores; } - float cpuSpeedInMHz() const { return mCPUMHz; } - bool isSSE() const { return mIsSSE; } - bool isSSE2() const { return mIsSSE2; } - bool isSSE3() const { return mIsSSE3; } - bool isSSE41() const { return mIsSSE41; } - bool isSSE42() const { return mIsSSE42; } - bool isAVX() const { return mIsAVX; } - bool isAVX2() const { return mIsAVX2; } - bool isAVX512() const { return mIsAVX512; } - bool isHyperThreaded() const { return mIsHTT; } - int logicalCpus() const { return mNumLogCpus; } - - private: - // Bit positions for data extractions - static const uint32_t SSE_POS = 0x02000000; - static const uint32_t SSE2_POS = 0x04000000; - static const uint32_t SSE3_POS = 0x00000001; - static const uint32_t SSE41_POS = 0x00080000; - static const uint32_t SSE42_POS = 0x00100000; - static const uint32_t AVX_POS = 0x10000000; - static const uint32_t AVX2_POS = 0x00000020; - static const uint32_t AVX512_POS = 0x00010000; // AVX-512F bit in EBX from CPUID function 7 - static const uint32_t LVL_NUM = 0x000000FF; - static const uint32_t LVL_TYPE = 0x0000FF00; - static const uint32_t LVL_CORES = 0x0000FFFF; - - // Attributes - string mVendorId; - string mModelName; - int mNumSMT; - int mNumCores; - int mNumLogCpus; - float mCPUMHz; - bool mIsHTT; - bool mIsSSE; - bool mIsSSE2; - bool mIsSSE3; - bool mIsSSE41; - bool mIsSSE42; - bool mIsAVX; - bool mIsAVX2; - bool mIsAVX512; +class CPUInfo +{ +public: + CPUInfo(); + string vendor() const { return mVendorId; } + string model() const { return mModelName; } + int cores() const { return mNumCores; } + float cpuSpeedInMHz() const { return mCPUMHz; } + bool isSSE() const { return mIsSSE; } + bool isSSE2() const { return mIsSSE2; } + bool isSSE3() const { return mIsSSE3; } + bool isSSE41() const { return mIsSSE41; } + bool isSSE42() const { return mIsSSE42; } + bool isAVX() const { return mIsAVX; } + bool isAVX2() const { return mIsAVX2; } + bool isAVX512() const { return mIsAVX512; } + bool isHyperThreaded() const { return mIsHTT; } + int logicalCpus() const { return mNumLogCpus; } + +private: + // Bit positions for data extractions + static const uint32_t SSE_POS = 0x02000000; + static const uint32_t SSE2_POS = 0x04000000; + static const uint32_t SSE3_POS = 0x00000001; + static const uint32_t SSE41_POS = 0x00080000; + static const uint32_t SSE42_POS = 0x00100000; + static const uint32_t AVX_POS = 0x10000000; + static const uint32_t AVX2_POS = 0x00000020; + static const uint32_t AVX512_POS = 0x00010000; // AVX-512F bit in EBX from CPUID function 7 + static const uint32_t LVL_NUM = 0x000000FF; + static const uint32_t LVL_TYPE = 0x0000FF00; + static const uint32_t LVL_CORES = 0x0000FFFF; + + // Attributes + string mVendorId; + string mModelName; + int mNumSMT; + int mNumCores; + int mNumLogCpus; + float mCPUMHz; + bool mIsHTT; + bool mIsSSE; + bool mIsSSE2; + bool mIsSSE3; + bool mIsSSE41; + bool mIsSSE42; + bool mIsAVX; + bool mIsAVX2; + bool mIsAVX512; }; CPUInfo::CPUInfo() @@ -96,99 +100,139 @@ CPUInfo::CPUInfo() mVendorId += string((const char *)&cpuID0.ECX(), 4); // Get SSE instructions availability CPUID cpuID1(1, 0); - mIsHTT = cpuID1.EDX() & AVX_POS; - mIsSSE = cpuID1.EDX() & SSE_POS; - mIsSSE2 = cpuID1.EDX() & SSE2_POS; - mIsSSE3 = cpuID1.ECX() & SSE3_POS; + mIsHTT = cpuID1.EDX() & AVX_POS; + mIsSSE = cpuID1.EDX() & SSE_POS; + mIsSSE2 = cpuID1.EDX() & SSE2_POS; + mIsSSE3 = cpuID1.ECX() & SSE3_POS; mIsSSE41 = cpuID1.ECX() & SSE41_POS; mIsSSE42 = cpuID1.ECX() & SSE41_POS; - mIsAVX = cpuID1.ECX() & AVX_POS; + mIsAVX = cpuID1.ECX() & AVX_POS; // Get AVX2 and AVX512 instructions availability CPUID cpuID7(7, 0); - mIsAVX2 = cpuID7.EBX() & AVX2_POS; + mIsAVX2 = cpuID7.EBX() & AVX2_POS; mIsAVX512 = cpuID7.EBX() & AVX512_POS; string upVId = mVendorId; - for_each(upVId.begin(), upVId.end(), [](char& in) { in = ::toupper(in); }); + for_each(upVId.begin(), upVId.end(), [](char &in) + { in = ::toupper(in); }); // Get num of cores - if (upVId.find("INTEL") != std::string::npos) { - if(HFS >= 11) { - for (int lvl=0; lvl>8; - switch(currLevel) { - case 0x01: mNumSMT = LVL_CORES & cpuID4.EBX(); break; - case 0x02: mNumLogCpus = LVL_CORES & cpuID4.EBX(); break; - default: break; - } + if (upVId.find("INTEL") != std::string::npos) + { + if (HFS >= 11) + { + for (int lvl = 0; lvl < MAX_INTEL_TOP_LVL; ++lvl) + { + CPUID cpuID4(0x0B, lvl); + uint32_t currLevel = (LVL_TYPE & cpuID4.ECX()) >> 8; + switch (currLevel) + { + case 0x01: + mNumSMT = LVL_CORES & cpuID4.EBX(); + break; + case 0x02: + mNumLogCpus = LVL_CORES & cpuID4.EBX(); + break; + default: + break; + } } - mNumCores = mNumLogCpus/mNumSMT; - } else { - if (HFS>=1) { + mNumCores = mNumLogCpus / mNumSMT; + } + else + { + if (HFS >= 1) + { mNumLogCpus = (cpuID1.EBX() >> 16) & 0xFF; - if (HFS>=4) { + if (HFS >= 4) + { mNumCores = 1 + (CPUID(4, 0).EAX() >> 26) & 0x3F; } } - if (mIsHTT) { - if (!(mNumCores>1)) { + if (mIsHTT) + { + if (!(mNumCores > 1)) + { mNumCores = 1; mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2); } - } else { + } + else + { mNumCores = mNumLogCpus = 1; } } - } else if (upVId.find("AMD") != std::string::npos) { - if (HFS>=1) { + } + else if (upVId.find("AMD") != std::string::npos) + { + if (HFS >= 1) + { mNumLogCpus = (cpuID1.EBX() >> 16) & 0xFF; - if (CPUID(0x80000000, 0).EAX() >=8) { + if (CPUID(0x80000000, 0).EAX() >= 8) + { mNumCores = 1 + (CPUID(0x80000008, 0).ECX() & 0xFF); } } - if (mIsHTT) { - if (!(mNumCores>1)) { + if (mIsHTT) + { + if (!(mNumCores > 1)) + { mNumCores = 1; mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2); } - } else { + } + else + { mNumCores = mNumLogCpus = 1; } - } else { - cout<< "Unexpected vendor id" </$1", "@commanders/(.*)$": "/../src/infrastructure/commanders/$1" } + }, + "pkg": { + "scripts": "command/**/*.js", + "assets": ["command/*.node", "**/package.json", "node_modules/axios/**/*", "cpuinfo/**/*"], + "outputPath": "dist" } } diff --git a/cortex-js/src/infrastructure/commanders/init.command.ts b/cortex-js/src/infrastructure/commanders/init.command.ts index 38cde473..30a80143 100644 --- a/cortex-js/src/infrastructure/commanders/init.command.ts +++ b/cortex-js/src/infrastructure/commanders/init.command.ts @@ -38,7 +38,7 @@ export class InitCommand extends CommandRunner { if (options?.silent) { const installationOptions = await this.initUsecases.defaultInstallationOptions(); - return this.initUsecases.installEngine(installationOptions); + await this.initUsecases.installEngine(installationOptions); } else { options = await this.inquirerService.ask( 'init-run-mode-questions', @@ -57,6 +57,7 @@ export class InitCommand extends CommandRunner { TelemetrySource.CLI, ); } + console.log('Cortex engines installed successfully!'); } @Option({ diff --git a/cortex-js/src/infrastructure/commanders/test/models.command.spec.ts b/cortex-js/src/infrastructure/commanders/test/models.command.spec.ts index e5434eb1..a40f49dc 100644 --- a/cortex-js/src/infrastructure/commanders/test/models.command.spec.ts +++ b/cortex-js/src/infrastructure/commanders/test/models.command.spec.ts @@ -4,7 +4,6 @@ import { CommandTestFactory } from 'nest-commander-testing'; import { CommandModule } from '@/command.module'; import { join } from 'path'; import { rmSync } from 'fs'; -import { timeout } from '@/infrastructure/commanders/test/helpers.command.spec'; import { FileManagerService } from '@/infrastructure/services/file-manager/file-manager.service'; let commandInstance: TestingModule; diff --git a/cortex-js/src/infrastructure/commanders/usecases/init.cli.usecases.ts b/cortex-js/src/infrastructure/commanders/usecases/init.cli.usecases.ts index 101776d1..4b6cb1e1 100644 --- a/cortex-js/src/infrastructure/commanders/usecases/init.cli.usecases.ts +++ b/cortex-js/src/infrastructure/commanders/usecases/init.cli.usecases.ts @@ -1,5 +1,5 @@ import { cpSync, createWriteStream, existsSync, readdirSync, rmSync } from 'fs'; -import { delimiter, join } from 'path'; +import { join } from 'path'; import { HttpService } from '@nestjs/axios'; import { Presets, SingleBar } from 'cli-progress'; import decompress from 'decompress'; @@ -9,8 +9,6 @@ import { Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; import { FileManagerService } from '@/infrastructure/services/file-manager/file-manager.service'; import { rm } from 'fs/promises'; -import { exec } from 'child_process'; -import { appPath } from '@/utils/app-path'; import { CORTEX_ENGINE_RELEASES_URL, CORTEX_RELEASES_URL, @@ -18,7 +16,8 @@ import { } from '@/infrastructure/constants/cortex'; import { checkNvidiaGPUExist, cudaVersion } from '@/utils/cuda'; import { Engines } from '../types/engine.interface'; -import { checkModelCompatibility } from '@/utils/model-check'; + +import { cpuInfo } from 'cpuinfo'; @Injectable() export class InitCliUsecases { @@ -271,35 +270,9 @@ export class InitCliUsecases { private detectInstructions = (): Promise< 'AVX' | 'AVX2' | 'AVX512' | undefined > => { - return new Promise<'AVX' | 'AVX2' | 'AVX512' | undefined>((res) => { - // Execute the cpuinfo command - - exec( - join( - appPath, - `bin/cpuinfo${process.platform !== 'linux' ? '.exe' : ''}`, - ), - (error, stdout) => { - if (error) { - // If there's an error, it means lscpu is not installed - console.log('CPUInfo is not installed.'); - res('AVX'); - } else { - // If the command executes successfully, parse the output to detect CPU instructions - if (stdout.includes('"AVX512": "true"')) { - console.log('AVX-512 instructions detected.'); - res('AVX512'); - } else if ('"AVX2": "true"') { - console.log('AVX2 instructions detected.'); - res('AVX2'); - } else { - console.log('AVXs instructions detected.'); - res('AVX'); - } - } - }, - ); - }); + const cpuInstruction = cpuInfo.cpuInfo()[0]?? 'AVX' + console.log(cpuInstruction, 'CPU instructions detected'); + return Promise.resolve(cpuInstruction); }; /** diff --git a/cortex-js/src/usecases/models/models.usecases.ts b/cortex-js/src/usecases/models/models.usecases.ts index 036a6d8b..5de6b8ae 100644 --- a/cortex-js/src/usecases/models/models.usecases.ts +++ b/cortex-js/src/usecases/models/models.usecases.ts @@ -348,7 +348,8 @@ export class ModelsUsecases { const toDownloads: Record = files .filter((e) => this.validFileDownload(e)) .reduce((acc: Record, file) => { - acc[file.downloadUrl] = join(modelFolder, file.rfilename); + if (file.downloadUrl) + acc[file.downloadUrl] = join(modelFolder, file.rfilename); return acc; }, {});