From ae9c6626d3ba8c5f11f9c352526ff17f14dbc180 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 15:31:36 +0200 Subject: [PATCH 1/9] depracate '-n'. --- eth/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/main.cpp b/eth/main.cpp index db6acbbca..5bc6f9911 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -342,6 +342,8 @@ int main(int argc, char** argv) exportTo = exportFrom = argv[++i]; else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc) { + if (arg == "-n") + cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use -u instead." << endl; string m = argv[++i]; if (isTrue(m)) upnp = true; From eaa4f43432927cc54349da1c719654e7c1f8acf2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 15:37:03 +0200 Subject: [PATCH 2/9] -DHEADLESS is DEPRECATED!!! --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c90dec46..d40d76ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ else () endif () # Backwards compatibility if (HEADLESS) + message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") set(BUNDLE "minimal") endif () From aa686b1c0f764797e4a65393718ded21881e1deb Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Apr 2015 16:41:21 +0200 Subject: [PATCH 3/9] Test Case for Miner Selection features. --- mix/qml/StateDialog.qml | 17 +++++++++++++++-- mix/qml/StateListModel.qml | 4 +++- mix/test/qml/TestMain.qml | 3 +++ mix/test/qml/js/TestMiner.js | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 mix/test/qml/js/TestMiner.js diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index d609808ea..a2f9a09b7 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -22,6 +22,8 @@ Dialog { property alias isDefault: defaultCheckBox.checked property alias model: transactionsModel property alias transactionDialog: transactionDialog + property alias minerComboBox: comboMiner + property alias newAccAction: newAccountAction property int stateIndex property var stateTransactions: [] property var stateAccounts: [] @@ -46,12 +48,11 @@ Dialog { accountsModel.clear(); stateAccounts = []; var miner = 0; - for (var k = 0; k < item.accounts.length; k++) { accountsModel.append(item.accounts[k]); stateAccounts.push(item.accounts[k]); - if (item.accounts[k].name === item.miner.name) + if (item.miner && item.accounts[k].name === item.miner.name) miner = k; } @@ -91,6 +92,7 @@ Dialog { } return item; } + contentItem: Rectangle { color: stateDialogStyle.generic.backgroundColor Rectangle { @@ -138,6 +140,7 @@ Dialog { Button { + id: newAccountButton anchors.top: accountsLabel.bottom anchors.topMargin: 10 iconSource: "qrc:/qml/img/plus.png" @@ -148,10 +151,16 @@ Dialog { id: newAccountAction tooltip: qsTr("Add new Account") onTriggered: + { + add(); + } + + function add() { var account = stateListModel.newAccount("1000000", QEther.Ether); stateAccounts.push(account); accountsModel.append(account); + return account; } } } @@ -194,8 +203,12 @@ Dialog { alertAlreadyUsed.open(); else { + if (stateAccounts[styleData.row].name === comboMiner.currentText) + comboMiner.currentIndex = 0; stateAccounts.splice(styleData.row, 1); accountsModel.remove(styleData.row); + comboMiner.model = stateAccounts; + comboMiner.update(); } } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index fbb384caf..35d106b5f 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -193,7 +193,9 @@ Item { accounts: [] }; - item.accounts.push(newAccount("1000000", QEther.Ether, defaultAccount)); + var account = newAccount("1000000", QEther.Ether, defaultAccount) + item.accounts.push(account); + item.miner = account; //add all stdc contracts for (var i = 0; i < contractLibrary.model.count; i++) { diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index bf449d2dd..69f37f5a4 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -4,6 +4,7 @@ import org.ethereum.qml.TestService 1.0 import "../../qml" import "js/TestDebugger.js" as TestDebugger import "js/TestTutorial.js" as TestTutorial +import "js/TestMiner.js" as TestMiner TestCase { @@ -74,5 +75,7 @@ TestCase function test_dbg_transactionWithParameter() { TestDebugger.test_transactionWithParameter(); } function test_dbg_constructorParameters() { TestDebugger.test_constructorParameters(); } function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } + function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } + function test_miner_selectMiner() { TestMiner.test_selectMiner(); } } diff --git a/mix/test/qml/js/TestMiner.js b/mix/test/qml/js/TestMiner.js new file mode 100644 index 000000000..a24b0ce19 --- /dev/null +++ b/mix/test/qml/js/TestMiner.js @@ -0,0 +1,20 @@ +function test_getDefaultMiner() +{ + newProject(); + var state = mainApplication.projectModel.stateListModel.get(0); + compare(state.miner.secret, "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); +} + +function test_selectMiner() +{ + newProject(); + mainApplication.projectModel.stateListModel.editState(0); + var account = mainApplication.projectModel.stateDialog.newAccAction.add(); + account = mainApplication.projectModel.stateDialog.newAccAction.add(); + mainApplication.projectModel.stateDialog.minerComboBox.currentIndex = 2; + ts.waitForRendering(mainApplication.projectModel.stateDialog.minerComboBox, 3000); + mainApplication.projectModel.stateDialog.acceptAndClose(); + var state = mainApplication.projectModel.stateListModel.get(0); + compare(state.miner.secret, account.secret); +} + From 8d2141fdf8b985f24612ba13f6dfcfd242fa206a Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Apr 2015 16:52:23 +0200 Subject: [PATCH 4/9] fixed bad commit --- mix/test/qml/TestMain.qml | 3 --- 1 file changed, 3 deletions(-) diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index fb0c01adf..d1d962900 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -76,11 +76,8 @@ TestCase function test_dbg_transactionWithParameter() { TestDebugger.test_transactionWithParameter(); } function test_dbg_constructorParameters() { TestDebugger.test_constructorParameters(); } function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } -<<<<<<< HEAD function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } function test_miner_selectMiner() { TestMiner.test_selectMiner(); } -======= function test_project_contractRename() { TestProject.test_contractRename(); } ->>>>>>> up/develop } From b5e9ab0a6fd5f12af48b76dfc76335b48837c4c0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 19:05:34 +0200 Subject: [PATCH 5/9] GPU/CPU Mining benchmarking. --- CMakeLists.txt | 18 +++- cmake/EthDependencies.cmake | 10 +- cmake/FindCpuid.cmake | 33 +++++++ eth/main.cpp | 157 ++++++++++++++++++++++++++++--- libethash-cl/ethash_cl_miner.cpp | 27 ++++++ libethash-cl/ethash_cl_miner.h | 1 + libethcore/CMakeLists.txt | 7 ++ libethcore/Ethash.cpp | 62 ++++++++++++ libethcore/Ethash.h | 2 + libethcore/Miner.h | 7 +- libethereum/Farm.h | 11 +++ 11 files changed, 316 insertions(+), 19 deletions(-) create mode 100644 cmake/FindCpuid.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d40d76ef2..2641f1bda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,14 @@ function(configureProject) add_definitions(-DETH_GUI) endif() + if (CPUID_FOUND) + add_definitions(-DETH_CPUID) + endif() + + if (CURL_FOUND) + add_definitions(-DETH_CURL) + endif() + add_definitions(-DETH_TRUE) endfunction() @@ -272,8 +280,6 @@ elseif (BUNDLE STREQUAL "user") set(TESTS OFF) endif () -configureProject() - # Default CMAKE_BUILD_TYPE to "Release". set(CMAKE_BUILD_TYPE CACHE STRING "Release") if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x") @@ -290,6 +296,10 @@ if ("x${TARGET_PLATFORM}" STREQUAL "x") endif () endif () +include(EthDependencies) + +configureProject() + message("------------------------------------------------------------------------") message("-- CMake Version ${CMAKE_VERSION}") message("-- CMAKE_BUILD_TYPE Build type ${CMAKE_BUILD_TYPE}") @@ -297,6 +307,8 @@ message("-- TARGET_PLATFORM Target platform ${TARGET_P message("-- BUNDLE Build bundle ${BUNDLE}") message("--------------------------------------------------------------- features") message("-- Chromium support ${ETH_HAVE_WEBENGINE}") +message("-- Hardware identification support ${CPUID_FOUND}") +message("-- HTTP Request support ${CURL_FOUND}") message("-- VMTRACE VM execution tracing ${VMTRACE}") message("-- PROFILING Profiling support ${PROFILING}") message("-- FATDB Full database exploring ${FATDB}") @@ -322,9 +334,7 @@ endif () include(EthCompilerSettings) message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") - # this must be an include, as a function it would mess up with variable scope! -include(EthDependencies) include(EthExecutableHelper) createBuildInfo() diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 61c87efd2..4c6b7841a 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -59,7 +59,6 @@ if (JSONRPC) find_package(MHD) message(" - microhttpd header: ${MHD_INCLUDE_DIRS}") message(" - microhttpd lib : ${MHD_LIBRARIES}") - endif() #JSONRPC # TODO readline package does not yet check for correct version number @@ -86,7 +85,7 @@ endif() # TODO it is also not required in msvc build find_package (Gmp 6.0.0) if (GMP_FOUND) - message(" - gmp Header: ${GMP_INCLUDE_DIRS}") + message(" - gmp header: ${GMP_INCLUDE_DIRS}") message(" - gmp lib : ${GMP_LIBRARIES}") endif() @@ -96,6 +95,13 @@ find_package (CURL) message(" - curl header: ${CURL_INCLUDE_DIRS}") message(" - curl lib : ${CURL_LIBRARIES}") +# cpuid required for eth +find_package (Cpuid) +if (CPUID_FOUND) + message(" - cpuid header: ${CPUID_INCLUDE_DIRS}") + message(" - cpuid lib : ${CPUID_LIBRARIES}") +endif() + # find location of jsonrpcstub find_program(ETH_JSON_RPC_STUB jsonrpcstub) message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}") diff --git a/cmake/FindCpuid.cmake b/cmake/FindCpuid.cmake new file mode 100644 index 000000000..8b590f44b --- /dev/null +++ b/cmake/FindCpuid.cmake @@ -0,0 +1,33 @@ +# Find libcpuid +# +# Find the libcpuid includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# CPUID_INCLUDE_DIRS, where to find header, etc. +# CPUID_LIBRARIES, the libraries needed to use cpuid. +# CPUID_FOUND, If false, do not try to use cpuid. + +# only look in default directories +find_path( + CPUID_INCLUDE_DIR + NAMES libcpuid/libcpuid.h + DOC "libcpuid include dir" + ) + +find_library( + CPUID_LIBRARY + NAMES cpuid + DOC "libcpuid library" + ) + +set(CPUID_INCLUDE_DIRS ${CPUID_INCLUDE_DIR}) +set(CPUID_LIBRARIES ${CPUID_LIBRARY}) + +# handle the QUIETLY and REQUIRED arguments and set CPUID_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(cpuid DEFAULT_MSG CPUID_INCLUDE_DIR CPUID_LIBRARY) +mark_as_advanced (CPUID_INCLUDE_DIR CPUID_LIBRARY) + diff --git a/eth/main.cpp b/eth/main.cpp index 5bc6f9911..7da725b6c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -89,7 +89,7 @@ void interactiveHelp() << " send Execute a given transaction with current secret." << endl << " contract Create a new contract with current secret." << endl << " peers List the peers that are connected" << endl -#if ETH_FATDB +#if ETH_FATDB || !ETH_TRUE << " listaccounts List the accounts on the network." << endl << " listcontracts List the contracts on the network." << endl #endif @@ -112,24 +112,31 @@ void help() << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl << " -c,--client-name Add a name to your client's version string (default: blank)." << endl - << " -C,--check-pow Check PoW credentials for validity." << endl + << " -C,--cpu When mining, use the CPU." << endl << " -d,--db-path Load database from path (default: ~/.ethereum " << endl << " /Etherum or Library/Application Support/Ethereum)." << endl + << " --benchmark-warmup Set the duration of warmup for the benchmark tests (default: 15)." << endl + << " --benchmark-trial Set the duration for each trial for the benchmark tests (default: 3)." << endl + << " --benchmark-trials Set the duration of warmup for the benchmark tests (default: 5)." << endl << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl << " -E,--export Export file as a concatenated series of blocks and exit." << endl << " --from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --only Equivalent to --export-from n --export-to n." << endl - << " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl + << " -f,--force-mining Mine even when there are no transactions to mine (Default: off)" << endl +#if ETH_JSONRPC || !ETH_TRUE + << " -F,--farm Put into mining farm mode (default GPU with CPU as fallback)." << endl +#endif + << " -G,--gpu When miningm use the GPU." << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -I,--import Import file as a concatenated series of blocks and exit." << endl -#if ETH_JSONRPC +#if ETH_JSONRPC || !ETH_TRUE << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl #endif -#if ETH_EVMJIT +#if ETH_EVMJIT || !ETH_TRUE << " -J,--jit Enable EVM JIT (default: off)." << endl #endif << " -K,--kill First kill the blockchain." << endl @@ -137,17 +144,20 @@ void help() << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl << " -u,--public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl - << " -n,-u,--upnp Use upnp for NAT (default: on)." << endl + << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --gpu." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl << " -p,--port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl + << " --phone-home When benchmarking, publish results (Default: on)" << endl << " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -S,--temporary-secret Set the secret key for use with send command, for this session only." << endl + << " -u,--upnp Use upnp for NAT (default: on)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl - << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl + << " -w,--check-pow Check PoW credentials for validity." << endl + << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl ; exit(0); } @@ -221,7 +231,9 @@ enum class OperationMode Node, Import, Export, - DAGInit + DAGInit, + Benchmark, + Farm }; enum class Format @@ -231,6 +243,70 @@ enum class Format Human }; +enum class MinerType +{ + CPU, + GPU +}; + +void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) +{ + BlockInfo genesis = CanonBlockChain::genesis(); + genesis.difficulty = 1 << 18; + cdebug << genesis.boundary(); + + GenericFarm f; + f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + + string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + cout << "Benchmarking on platform: " << platformInfo << endl; + + cout << "Preparing DAG..." << endl; + Ethash::prep(genesis); + + genesis.difficulty = u256(1) << 63; + genesis.noteDirty(); + f.setWork(genesis); + if (_m == MinerType::CPU) + f.startCPU(); + else if (_m == MinerType::GPU) + f.startGPU(); + + map results; + uint64_t mean = 0; + uint64_t innerMean = 0; + for (unsigned i = 0; i <= _trials; ++i) + { + if (!i) + cout << "Warming up..." << endl; + else + cout << "Trial " << i << "... " << flush; + this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration)); + + auto mp = f.miningProgress(); + f.resetMiningProgress(); + if (!i) + continue; + auto rate = mp.rate(); + + cout << rate << endl; + results[rate] = mp; + mean += rate; + if (i > 1 && i < 5) + innerMean += rate; + } + f.stop(); + cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl; + cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl; + + (void)_phoneHome; + if (_phoneHome) + { + // TODO: send f.miningInfo() along with f.platformInfo() to Marian. + } + exit(0); +} + int main(int argc, char** argv) { // Init defaults @@ -240,6 +316,9 @@ int main(int argc, char** argv) OperationMode mode = OperationMode::Node; string dbPath; + /// Mining options + MinerType minerType = MinerType::CPU; + /// File name for import/export. string filename; @@ -287,6 +366,12 @@ int main(int argc, char** argv) double etherPrice = 30.679; double blockFees = 15.0; + /// Benchmarking params + bool phoneHome = true; + unsigned benchmarkWarmup = 15; + unsigned benchmarkTrial = 3; + unsigned benchmarkTrials = 5; + string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); if (b.size()) @@ -319,6 +404,21 @@ int main(int argc, char** argv) mode = OperationMode::Export; filename = argv[++i]; } + else if (arg == "-F" || arg == "--farm") + mode = OperationMode::Farm; + else if (arg == "--phone-home" && i + 1 < argc) + { + string m = argv[++i]; + if (isTrue(m)) + phoneHome = true; + else if (isFalse(m)) + phoneHome = false; + else + { + cerr << "Bad " << arg << " option: " << m << endl; + return -1; + } + } else if (arg == "--format" && i + 1 < argc) { string m = argv[++i]; @@ -355,6 +455,33 @@ int main(int argc, char** argv) return -1; } } + else if (arg == "--benchmark-warmup" && i + 1 < argc) + try { + benchmarkWarmup = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + else if (arg == "--benchmark-trial" && i + 1 < argc) + try { + benchmarkTrial = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + else if (arg == "--benchmark-trials" && i + 1 < argc) + try { + benchmarkTrials = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill") killChain = WithExisting::Kill; else if (arg == "-B" || arg == "--rebuild") @@ -362,8 +489,7 @@ int main(int argc, char** argv) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) clientName = argv[++i]; else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) - try - { + try { coinbase = h160(fromHex(argv[++i], WhenError::Throw)); } catch (BadHexCharacter&) @@ -376,6 +502,10 @@ int main(int argc, char** argv) cerr << "Bad " << arg << " option: " << argv[i] << endl; return -1; } + else if (arg == "-C" || arg == "--cpu") + minerType = MinerType::CPU; + else if (arg == "-G" || arg == "--gpu") + minerType = MinerType::GPU; else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) sigKey = KeyPair(h256(fromHex(argv[++i]))); else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc) @@ -405,7 +535,7 @@ int main(int argc, char** argv) return -1; } } - else if ((arg == "-C" || arg == "--check-pow") && i + 4 < argc) + else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc) { string m; try @@ -442,6 +572,8 @@ int main(int argc, char** argv) return -1; } } + else if (arg == "-M" || arg == "--benchmark") + mode = OperationMode::Benchmark; else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) { try @@ -564,6 +696,9 @@ int main(int argc, char** argv) if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) doInitDAG(initDAG); + if (mode == OperationMode::Benchmark) + doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials); + if (!clientName.empty()) clientName += "/"; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 016d8af58..c9a621e29 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -57,6 +57,33 @@ ethash_cl_miner::ethash_cl_miner() { } +std::string ethash_cl_miner::platform_info() +{ + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + debugf("No OpenCL platforms found.\n"); + return std::string(); + } + + // get GPU device of the default platform + std::vector devices; + platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + debugf("No OpenCL devices found.\n"); + return std::string(); + } + + // use default device + unsigned device_num = 0; + cl::Device& device = devices[device_num]; + std::string device_version = device.getInfo(); + + return "{ platform: '" + platforms[0].getInfo() + "', device: '" + device.getInfo() + "', version: '" + device_version + "' }"; +} + void ethash_cl_miner::finish() { if (m_queue()) diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index d3d9f0223..079000f55 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -23,6 +23,7 @@ public: ethash_cl_miner(); bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64); + static std::string platform_info(); void finish(); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index f562bc948..020480d67 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -11,11 +11,15 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) +if (CPUID_FOUND) + include_directories(${Cpuid_INCLUDE_DIRS}) +endif () set(EXECUTABLE ethcore) file(GLOB HEADERS "*.h") + if(ETH_STATIC) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() @@ -25,6 +29,9 @@ endif() target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) +if (CPUID_FOUND) + target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) +endif () install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index a777205e9..632bc278d 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,10 @@ #if ETH_ETHASHCL || !ETH_TRUE #include #endif +#if ETH_CPUID || !ETH_TRUE +#define HAVE_STDINT_H +#include +#endif #include "BlockInfo.h" #include "EthashAux.h" using namespace std; @@ -142,6 +147,58 @@ void Ethash::CPUMiner::workLoop() } } +static string jsonEncode(map const& _m) +{ + string ret = "{"; + + for (auto const& i: _m) + { + string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'"); + string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'"); + if (ret.size() > 1) + ret += ", "; + ret += "\"" + k + "\":\"" + v + "\""; + } + + return ret + "}"; +} + +std::string Ethash::CPUMiner::platformInfo() +{ + string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; +#if ETH_CPUID || !ETH_TRUE + if (!cpuid_present()) + return baseline; + struct cpu_raw_data_t raw; + struct cpu_id_t data; + if (cpuid_get_raw_data(&raw) < 0) + return baseline; + if (cpu_identify(&raw, &data) < 0) + return baseline; + map m; + m["vendor"] = data.vendor_str; + m["codename"] = data.cpu_codename; + m["brand"] = data.brand_str; + m["L1 cache"] = toString(data.l1_data_cache); + m["L2 cache"] = toString(data.l2_cache); + m["L3 cache"] = toString(data.l3_cache); + m["cores"] = toString(data.num_cores); + m["threads"] = toString(data.num_logical_cpus); + m["clocknominal"] = toString(cpu_clock_by_os()); + m["clocktested"] = toString(cpu_clock_measure(200, 0)); + /* + printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent"); + printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent"); + printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent"); + printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent"); + printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent"); + */ + return jsonEncode(m); +#else + return baseline; +#endif +} + #if ETH_ETHASHCL || !ETH_TRUE class EthashCLHook: public ethash_cl_miner::search_hook @@ -258,6 +315,11 @@ void Ethash::GPUMiner::pause() stopWorking(); } +std::string Ethash::GPUMiner::platformInfo() +{ + return ethash_cl_miner::platform_info(); +} + #endif } diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 06e6b9e96..0d33d43a8 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -85,6 +85,7 @@ public: CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return std::thread::hardware_concurrency(); } + static std::string platformInfo(); protected: void kickOff() override @@ -109,6 +110,7 @@ public: ~GPUMiner(); static unsigned instances() { return 1; } + static std::string platformInfo(); protected: void kickOff() override; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 51a0ff6f6..71e952d5c 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -42,13 +42,14 @@ struct MiningProgress // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return hashes * 1000 / ms; } }; struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) { - _out << (_p.hashes * 1000 / _p.ms) << "H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << "s"; + _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; } @@ -112,7 +113,9 @@ public: m_hashCount = 0; } - uint64_t hashCount() { return m_hashCount; } + uint64_t hashCount() const { return m_hashCount; } + + void resetHashCount() { m_hashCount = 0; } unsigned index() const { return m_index; } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 26d4b139e..869925098 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -118,6 +118,17 @@ public: return m_progress; } + /** + * @brief Reset the mining progess counter. + */ + void resetMiningProgress() + { + ETH_READ_GUARDED(x_minerWork) + for (auto const& i: m_miners) + i->resetHashCount(); + resetTimer(); + } + using SolutionFound = std::function; /** From aa6b3c28ccc58f722f6b5c370d1f5ee3b9b6e6cd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 20:59:40 +0200 Subject: [PATCH 6/9] Allow device selection. --- eth/main.cpp | 24 +++++++++++++++++++++--- libethash-cl/ethash_cl_miner.cpp | 11 ++++++++--- libethash-cl/ethash_cl_miner.h | 2 +- libethcore/Ethash.cpp | 4 +++- libethcore/Ethash.h | 4 ++++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 7da725b6c..bc7d4875c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -38,14 +38,17 @@ #include #include #include -#if ETH_READLINE +#if ETH_READLINE || !ETH_TRUE #include #include #endif -#if ETH_JSONRPC +#if ETH_JSONRPC || !ETH_TRUE #include #include #endif +#if ETH_CURL || !ETH_TRUE +#include +#endif #include "BuildInfo.h" using namespace std; using namespace dev; @@ -128,7 +131,7 @@ void help() #if ETH_JSONRPC || !ETH_TRUE << " -F,--farm Put into mining farm mode (default GPU with CPU as fallback)." << endl #endif - << " -G,--gpu When miningm use the GPU." << endl + << " -G,--gpu When mining use the GPU." << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -I,--import Import file as a concatenated series of blocks and exit." << endl @@ -146,6 +149,7 @@ void help() << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --gpu." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl + << " --opencl-device When mining use OpenCL device n (default: 0)." << endl << " -p,--port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl << " --phone-home When benchmarking, publish results (Default: on)" << endl @@ -302,6 +306,8 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u (void)_phoneHome; if (_phoneHome) { + cout << "Phoning home to find world ranking..." << endl; + // TODO: send f.miningInfo() along with f.platformInfo() to Marian. } exit(0); @@ -318,6 +324,7 @@ int main(int argc, char** argv) /// Mining options MinerType minerType = MinerType::CPU; + unsigned openclDevice = 0; /// File name for import/export. string filename; @@ -406,6 +413,15 @@ int main(int argc, char** argv) } else if (arg == "-F" || arg == "--farm") mode = OperationMode::Farm; + else if (arg == "--opencl-device" && i + 1 < argc) + try { + openclDevice = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -718,6 +734,8 @@ int main(int argc, char** argv) if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); + ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); + auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index c9a621e29..56ac44e6b 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -92,7 +92,7 @@ void ethash_cl_miner::finish() } } -bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size) +bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _deviceId) { // store params m_params = params; @@ -119,8 +119,13 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function(_deviceId, devices.size() - 1)]; + for (unsigned n = 0; n < devices.size(); ++n) + { + auto version = devices[n].getInfo(); + auto name = devices[n].getInfo(); + fprintf(stderr, "%s %d: %s (%s)\n", n == _deviceId ? "USING " : " ", n, name.c_str(), version.c_str()); + } std::string device_version = device.getInfo(); fprintf(stderr, "Using device: %s (%s)\n", device.getInfo().c_str(),device_version.c_str()); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 079000f55..c699a2d83 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -22,7 +22,7 @@ public: public: ethash_cl_miner(); - bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64); + bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _deviceId = 0); static std::string platform_info(); void finish(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 632bc278d..2307da9dc 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -261,6 +261,8 @@ private: Ethash::GPUMiner* m_owner = nullptr; }; +unsigned Ethash::GPUMiner::s_deviceId = 0; + Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), m_hook(new EthashCLHook(this)) @@ -302,7 +304,7 @@ void Ethash::GPUMiner::workLoop() auto p = EthashAux::params(m_minerSeed); auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32); + m_miner->init(p, cb, 32, s_deviceId); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 0d33d43a8..077da4460 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -86,6 +86,7 @@ public: static unsigned instances() { return std::thread::hardware_concurrency(); } static std::string platformInfo(); + static void setDefaultDevice(unsigned) {} protected: void kickOff() override @@ -98,6 +99,7 @@ public: private: void workLoop() override; + static unsigned s_deviceId; }; #if ETH_ETHASHCL || !ETH_TRUE @@ -111,6 +113,7 @@ public: static unsigned instances() { return 1; } static std::string platformInfo(); + static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } protected: void kickOff() override; @@ -126,6 +129,7 @@ public: ethash_cl_miner* m_miner = nullptr; h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_deviceId; }; #else using GPUMiner = CPUMiner; From fff8c42240787951b4770a257a43b4b978956391 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 21:02:00 +0200 Subject: [PATCH 7/9] Fix for previous. --- eth/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index bc7d4875c..c88ce1b1b 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -707,6 +707,8 @@ int main(int argc, char** argv) if (sessionSecret) sigKey = KeyPair(sessionSecret); + ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); + // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) @@ -734,8 +736,6 @@ int main(int argc, char** argv) if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); - ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); - auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); From 28f2badc38d1b4a06fe355cafbc672a6b7f432a0 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 21:04:48 +0200 Subject: [PATCH 8/9] cleanup in ethashcl --- cmake/EthDependencies.cmake | 6 ++++ eth/CMakeLists.txt | 1 + libethash-cl/CMakeLists.txt | 52 ++++++++-------------------------- libethash-cl/ethash_cl_miner.h | 9 ++++++ libethcore/CMakeLists.txt | 3 +- libethereum/CMakeLists.txt | 1 - 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 4c6b7841a..4d79d7911 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -102,6 +102,12 @@ if (CPUID_FOUND) message(" - cpuid lib : ${CPUID_LIBRARIES}") endif() +find_package (OpenCL) +if (OpenCL_FOUND) + message(" - opencl header: ${OpenCL_INCLUDE_DIRES}") + message(" - opencl lib : ${OpenCL_LIBRARIES}") +endif() + # find location of jsonrpcstub find_program(ETH_JSON_RPC_STUB jsonrpcstub) message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}") diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index fbc6a8b24..557707f62 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -27,6 +27,7 @@ endif() target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} ethash-cl) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt index 7b00a22bd..d5f6792e1 100644 --- a/libethash-cl/CMakeLists.txt +++ b/libethash-cl/CMakeLists.txt @@ -1,47 +1,19 @@ -cmake_minimum_required(VERSION 2.8) - -set(LIBRARY ethash-cl) -#set(CMAKE_BUILD_TYPE Release) +set(EXECUTABLE ethash-cl) include(bin2h.cmake) bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl - VARIABLE_NAME ethash_cl_miner_kernel - HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) - -if (NOT MSVC) - # Initialize CXXFLAGS for c++11 - set(CMAKE_CXX_FLAGS "-Wall -std=c++11") - set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + VARIABLE_NAME ethash_cl_miner_kernel + HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) - # Compiler-specific C++11 activation. - if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) - message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") - endif () - elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - else () - message(FATAL_ERROR "Your C++ compiler does not support C++11.") - endif () -endif() +aux_source_directory(. SRC_LIST) +file(GLOB HEADERS "*.h") -set(OpenCL_FOUND TRUE) -set(OpenCL_INCLUDE_DIRS /usr/include/CL) -set(OpenCL_LIBRARIES -lOpenCL) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${OpenCL_INCLUDE_DIRS}}) +include_directories(..) +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) +TARGET_LINK_LIBRARIES(${EXECUTABLE} ${OpenCL_LIBRARIES} ethash) -if (NOT OpenCL_FOUND) - find_package(OpenCL) -endif() +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) -if (OpenCL_FOUND) - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}") - include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) - include_directories(..) - add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp) - TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash) -endif() diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 079000f55..2776b7378 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -2,7 +2,16 @@ #define __CL_ENABLE_EXCEPTIONS #define CL_USE_DEPRECATED_OPENCL_2_0_APIS + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#include "cl.hpp" +#pragma clang diagnostic pop +#else #include "cl.hpp" +#endif + #include #include #include diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 020480d67..c425c444d 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -19,7 +19,6 @@ set(EXECUTABLE ethcore) file(GLOB HEADERS "*.h") - if(ETH_STATIC) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() @@ -29,6 +28,8 @@ endif() target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) +target_link_libraries(${EXECUTABLE} ethash-cl) + if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 8822394a3..362713663 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -36,7 +36,6 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} OpenCL) endif () if (CMAKE_COMPILER_IS_MINGW) From 5d660495f599d03678e7dc8dae1d52652bc721ac Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 21:16:38 +0200 Subject: [PATCH 9/9] Linux, Mac building with OpenCL. --- cmake/CMakeParseArguments.cmake | 161 +++++++++ cmake/FindOpenCL.cmake | 136 ++++++++ cmake/FindPackageHandleStandardArgs.cmake | 382 ++++++++++++++++++++++ cmake/FindPackageMessage.cmake | 57 ++++ eth/main.cpp | 11 + 5 files changed, 747 insertions(+) create mode 100644 cmake/CMakeParseArguments.cmake create mode 100644 cmake/FindOpenCL.cmake create mode 100644 cmake/FindPackageHandleStandardArgs.cmake create mode 100644 cmake/FindPackageMessage.cmake diff --git a/cmake/CMakeParseArguments.cmake b/cmake/CMakeParseArguments.cmake new file mode 100644 index 000000000..8553f38f5 --- /dev/null +++ b/cmake/CMakeParseArguments.cmake @@ -0,0 +1,161 @@ +#.rst: +# CMakeParseArguments +# ------------------- +# +# +# +# CMAKE_PARSE_ARGUMENTS( +# args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions +# for parsing the arguments given to that macro or function. It +# processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any +# value following, like e.g. the OPTIONAL keyword of the install() +# command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this +# macro which can be followed by more than one value, like e.g. the +# TARGETS or FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. These +# variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see +# whether your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments +# as the real install() command: +# +# :: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" +# "${multiValueArgs}" ${ARGN} ) +# ... +# +# +# +# Assume my_install() has been called like this: +# +# :: +# +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# +# +# After the cmake_parse_arguments() call the macro will have set the +# following variables: +# +# :: +# +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# +# +# You can then continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a +# one_value_keyword another recognized keyword follows, this is +# interpreted as the beginning of the new option. E.g. +# my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION +# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach() + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach() + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else() + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif() + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach() + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach() + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction() diff --git a/cmake/FindOpenCL.cmake b/cmake/FindOpenCL.cmake new file mode 100644 index 000000000..4d3ed842c --- /dev/null +++ b/cmake/FindOpenCL.cmake @@ -0,0 +1,136 @@ +#.rst: +# FindOpenCL +# ---------- +# +# Try to find OpenCL +# +# Once done this will define:: +# +# OpenCL_FOUND - True if OpenCL was found +# OpenCL_INCLUDE_DIRS - include directories for OpenCL +# OpenCL_LIBRARIES - link against this library to use OpenCL +# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2) +# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation +# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation +# +# The module will also define two cache variables:: +# +# OpenCL_INCLUDE_DIR - the OpenCL include directory +# OpenCL_LIBRARY - the path to the OpenCL library +# + +#============================================================================= +# Copyright 2014 Matthaeus G. Chajdas +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(_FIND_OPENCL_VERSION) + include(CheckSymbolExists) + include(CMakePushCheckState) + set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY}) + + CMAKE_PUSH_CHECK_STATE() + foreach(VERSION "2_0" "1_2" "1_1" "1_0") + set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}") + + if(APPLE) + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/OpenCL/cl.h" + OPENCL_VERSION_${VERSION}) + else() + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/CL/cl.h" + OPENCL_VERSION_${VERSION}) + endif() + + if(OPENCL_VERSION_${VERSION}) + string(REPLACE "_" "." VERSION "${VERSION}") + set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE) + string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}") + list(GET version_components 0 major_version) + list(GET version_components 1 minor_version) + set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE) + set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE) + break() + endif() + endforeach() + CMAKE_POP_CHECK_STATE() +endfunction() + +find_path(OpenCL_INCLUDE_DIR + NAMES + CL/cl.h OpenCL/cl.h + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV NVSDKCOMPUTE_ROOT + ENV CUDA_PATH + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + include + OpenCL/common/inc + "AMD APP/include") + +_FIND_OPENCL_VERSION() + +if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86" + lib/x86 + lib/Win32 + OpenCL/common/lib/Win32) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86_64" + lib/x86_64 + lib/x64 + OpenCL/common/lib/x64) + endif() +else() + find_library(OpenCL_LIBRARY + NAMES OpenCL) +endif() + +set(OpenCL_LIBRARIES ${OpenCL_LIBRARY}) +set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args( + OpenCL + FOUND_VAR OpenCL_FOUND + REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR + VERSION_VAR OpenCL_VERSION_STRING) + +mark_as_advanced( + OpenCL_INCLUDE_DIR + OpenCL_LIBRARY) diff --git a/cmake/FindPackageHandleStandardArgs.cmake b/cmake/FindPackageHandleStandardArgs.cmake new file mode 100644 index 000000000..6bcf1e788 --- /dev/null +++ b/cmake/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,382 @@ +#.rst: +# FindPackageHandleStandardArgs +# ----------------------------- +# +# +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) +# +# This function is intended to be used in FindXXX.cmake modules files. +# It handles the REQUIRED, QUIET and version-related arguments to +# find_package(). It also sets the _FOUND variable. The +# package is considered found if all variables ... listed contain +# valid results, e.g. valid filepaths. +# +# There are two modes of this function. The first argument in both +# modes is the name of the Find-module where it is called (in original +# casing). +# +# The first simple mode looks like this: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( +# (DEFAULT_MSG|"Custom failure message") ... ) +# +# If the variables to are all valid, then +# _FOUND will be set to TRUE. If DEFAULT_MSG is given +# as second argument, then the function will generate itself useful +# success and error messages. You can also supply a custom error +# message for the failure case. This is not recommended. +# +# The second mode is more powerful and also supports version checking: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME +# [FOUND_VAR ] +# [REQUIRED_VARS ...] +# [VERSION_VAR ] +# [HANDLE_COMPONENTS] +# [CONFIG_MODE] +# [FAIL_MESSAGE "Custom failure message"] ) +# +# In this mode, the name of the result-variable can be set either to +# either _FOUND or _FOUND using the +# FOUND_VAR option. Other names for the result-variable are not +# allowed. So for a Find-module named FindFooBar.cmake, the two +# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended +# to use the original case version. If the FOUND_VAR option is not +# used, the default is _FOUND. +# +# As in the simple mode, if through are all valid, +# _FOUND will be set to TRUE. After REQUIRED_VARS the +# variables which are required for this package are listed. Following +# VERSION_VAR the name of the variable can be specified which holds the +# version of the package which has been found. If this is done, this +# version will be checked against the (potentially) specified required +# version used in the find_package() call. The EXACT keyword is also +# handled. The default messages include information about the required +# version and the version which has been actually found, both if the +# version is ok or not. If the package supports components, use the +# HANDLE_COMPONENTS option to enable handling them. In this case, +# find_package_handle_standard_args() will report which components have +# been found and which are missing, and the _FOUND variable +# will be set to FALSE if any of the required components (i.e. not the +# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option +# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a +# find_package(... NO_MODULE) call. In this case VERSION_VAR will be +# set to _VERSION and the macro will automatically check whether +# the Config module was found. Via FAIL_MESSAGE a custom failure +# message can be specified, if this is not used, the default message +# will be displayed. +# +# Example for mode 1: +# +# :: +# +# find_package_handle_standard_args(LibXml2 DEFAULT_MSG +# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# +# +# +# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and +# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to +# TRUE. If it is not found and REQUIRED was used, it fails with +# FATAL_ERROR, independent whether QUIET was used or not. If it is +# found, success will be reported, including the content of . On +# repeated Cmake runs, the same message won't be printed again. +# +# Example for mode 2: +# +# :: +# +# find_package_handle_standard_args(LibXslt +# FOUND_VAR LibXslt_FOUND +# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS +# VERSION_VAR LibXslt_VERSION_STRING) +# +# In this case, LibXslt is considered to be found if the variable(s) +# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and +# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in +# LibXslt_FOUND . Also the version of LibXslt will be checked by using +# the version contained in LibXslt_VERSION_STRING. Since no +# FAIL_MESSAGE is given, the default messages will be printed. +# +# Another example for mode 2: +# +# :: +# +# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) +# find_package_handle_standard_args(Automoc4 CONFIG_MODE) +# +# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4 +# NO_MODULE) and adds an additional search directory for automoc4. Here +# the result will be stored in AUTOMOC4_FOUND. The following +# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper +# success/error message. + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake) + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${_msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${_msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + set(configsText "${configsText} ${filename} (version ${version})\n") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + set(options CONFIG_MODE HANDLE_COMPONENTS) + set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + endif() + +# now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$") + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + unset(${_FOUND_VAR}) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") + else() + set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE") + set(${_FOUND_VAR} TRUE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components: ") + endif() + set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components: ") + endif() + set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + set(VERSION ${${FPHSA_VERSION_VAR}}) + + # check with DEFINED here as the requested or found version may be "0" + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + + if(${_NAME}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}") + # add one dot because there is one dot more than there are components + string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) + if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) + set(_VERSION_REGEX "[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) + set(_VERSION_REGEX "[^.]*\\.[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") + else () + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif () + string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}") + unset(_VERSION_REGEX) + if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + unset(_VERSION_HEAD) + else () + if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + endif () + unset(_VERSION_DOTS) + + else() # minimum version specified: + if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") + endif () + endif() + + else() + + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + + endif() + else () + if(VERSION) + set(VERSION_MSG "(found version \"${VERSION}\")") + endif() + endif () + + if(VERSION_OK) + set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") + else() + set(${_FOUND_VAR} FALSE) + endif() + + + # print the result: + if (${_FOUND_VAR}) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE) + +endfunction() diff --git a/cmake/FindPackageMessage.cmake b/cmake/FindPackageMessage.cmake new file mode 100644 index 000000000..a0349d3db --- /dev/null +++ b/cmake/FindPackageMessage.cmake @@ -0,0 +1,57 @@ +#.rst: +# FindPackageMessage +# ------------------ +# +# +# +# FIND_PACKAGE_MESSAGE( "message for user" "find result details") +# +# This macro is intended to be used in FindXXX.cmake modules files. It +# will print a message once for each unique find result. This is useful +# for telling the user where a package was found. The first argument +# specifies the name (XXX) of the package. The second argument +# specifies the message to display. The third argument lists details +# about the find result so that if they change the message will be +# displayed again. The macro also obeys the QUIET argument to the +# find_package command. +# +# Example: +# +# :: +# +# if(X11_FOUND) +# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" +# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +# else() +# ... +# endif() + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(FIND_PACKAGE_MESSAGE pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/eth/main.cpp b/eth/main.cpp index c88ce1b1b..0896823d2 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -313,6 +313,14 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u exit(0); } +void doFarm(MinerType _m) +{ + (void)_m; + // TODO: Set up JSONRPC client: to implement: +// { "name": "eth_getWork", "params": [], "order": [], "returns": [, , ]}, +// { "name": "eth_submitWork", "params": [, ], "order": [], "returns": true}, +} + int main(int argc, char** argv) { // Init defaults @@ -717,6 +725,9 @@ int main(int argc, char** argv) if (mode == OperationMode::Benchmark) doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials); + if (mode == OperationMode::Farm) + doFarm(minerType); + if (!clientName.empty()) clientName += "/";