adding new branch for devolping

This commit is contained in:
Qiwei Ye 2016-02-02 20:40:07 +08:00
Родитель 97f1cce893
Коммит 07e81949db
155 изменённых файлов: 2222 добавлений и 23396 удалений

4
next/.gitignore поставляемый
Просмотреть файл

@ -19,3 +19,7 @@ windows/*.suo
windows/multiverso/*.user
windows/multiverso_server/*.user
windows/*/x64
*.opensdf
*.user
*sdf
*.suo

116
next/IMultiverso/IMultiverso.sln → next/IMultiverso.sln Executable file → Normal file
Просмотреть файл

@ -1,58 +1,58 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IMultiverso", "IMultiverso.vcxproj", "{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{546681D6-495C-4AEE-BBC2-3CAEC86B5137}"
EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 3
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http://vstfsng01:8080/tfs/research
SccLocalPath0 = .
SccProjectUniqueName1 = IMultiverso.vcxproj
SccLocalPath1 = .
SccProjectUniqueName2 = Test\\Test.vcxproj
SccProjectName2 = Test
SccLocalPath2 = Test
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.ActiveCfg = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.Build.0 = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.ActiveCfg = Release|x64
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.Build.0 = Release|x64
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.Build.0 = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.ActiveCfg = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.Build.0 = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.ActiveCfg = Release|x64
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.Build.0 = Release|x64
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.ActiveCfg = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.Build.0 = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|x64.ActiveCfg = Debug|x64
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.Build.0 = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.ActiveCfg = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.Build.0 = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.ActiveCfg = Release|x64
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IMultiverso", "IMultiverso.vcxproj", "{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{546681D6-495C-4AEE-BBC2-3CAEC86B5137}"
EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 3
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http://vstfsng01:8080/tfs/research
SccLocalPath0 = .
SccProjectUniqueName1 = IMultiverso.vcxproj
SccLocalPath1 = .
SccProjectUniqueName2 = Test\\Test.vcxproj
SccProjectName2 = Test
SccLocalPath2 = Test
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.ActiveCfg = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|Win32.Build.0 = Debug|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.ActiveCfg = Release|x64
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Debug|x64.Build.0 = Release|x64
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Mixed Platforms.Build.0 = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.ActiveCfg = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|Win32.Build.0 = Release|Win32
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.ActiveCfg = Release|x64
{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}.Release|x64.Build.0 = Release|x64
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.ActiveCfg = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|Win32.Build.0 = Debug|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Debug|x64.ActiveCfg = Debug|x64
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Mixed Platforms.Build.0 = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.ActiveCfg = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|Win32.Build.0 = Release|Win32
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.ActiveCfg = Release|x64
{546681D6-495C-4AEE-BBC2-3CAEC86B5137}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1,175 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>IMultiverso</RootNamespace>
<SccProjectName>SAK</SccProjectName>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(MSMPI_INC);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<AdditionalDependencies>msmpi.lib</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x64</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="new\actor.h" />
<ClInclude Include="new\blob.h" />
<ClInclude Include="new\communicator.h" />
<ClInclude Include="new\controller.h" />
<ClInclude Include="new\kv_table.h" />
<ClInclude Include="new\log.h" />
<ClInclude Include="new\message.h" />
<ClInclude Include="new\mt_queue.h" />
<ClInclude Include="new\multiverso.h" />
<ClInclude Include="new\net.h" />
<ClInclude Include="new\server.h" />
<ClInclude Include="new\table_interface.h" />
<ClInclude Include="new\waiter.h" />
<ClInclude Include="new\worker.h" />
<ClInclude Include="new\zoo.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="new\actor.cpp" />
<ClCompile Include="new\communicator.cpp" />
<ClCompile Include="new\controller.cpp" />
<ClCompile Include="new\log.cpp" />
<ClCompile Include="new\multiverso.cpp" />
<ClCompile Include="new\net.cpp" />
<ClCompile Include="new\server.cpp" />
<ClCompile Include="new\array_table.h" />
<ClCompile Include="new\table.cpp" />
<ClCompile Include="new\worker.cpp" />
<ClCompile Include="new\zoo.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F2DD7153-E4FB-4CA8-9B9E-CB6AB025CCBA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>IMultiverso</RootNamespace>
<SccProjectName>SAK</SccProjectName>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(MSMPI_INC);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<AdditionalDependencies>msmpi.lib</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x64</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="new\actor.h" />
<ClInclude Include="new\blob.h" />
<ClInclude Include="new\communicator.h" />
<ClInclude Include="new\controller.h" />
<ClInclude Include="new\kv_table.h" />
<ClInclude Include="new\log.h" />
<ClInclude Include="new\message.h" />
<ClInclude Include="new\mt_queue.h" />
<ClInclude Include="new\multiverso.h" />
<ClInclude Include="new\net.h" />
<ClInclude Include="new\server.h" />
<ClInclude Include="new\table_interface.h" />
<ClInclude Include="new\waiter.h" />
<ClInclude Include="new\worker.h" />
<ClInclude Include="new\zoo.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="new\actor.cpp" />
<ClCompile Include="new\communicator.cpp" />
<ClCompile Include="new\controller.cpp" />
<ClCompile Include="new\log.cpp" />
<ClCompile Include="new\multiverso.cpp" />
<ClCompile Include="new\net.cpp" />
<ClCompile Include="new\server.cpp" />
<ClCompile Include="new\array_table.h" />
<ClCompile Include="new\table.cpp" />
<ClCompile Include="new\worker.cpp" />
<ClCompile Include="new\zoo.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

Просмотреть файл

@ -1,99 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="new\kv_table.h">
<Filter>include\table</Filter>
</ClInclude>
<ClInclude Include="new\multiverso.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="new\table_interface.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="new\log.h">
<Filter>util</Filter>
</ClInclude>
<ClInclude Include="new\zoo.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\worker.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\actor.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\server.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\controller.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\communicator.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\waiter.h">
<Filter>util</Filter>
</ClInclude>
<ClInclude Include="new\mt_queue.h">
<Filter>util</Filter>
</ClInclude>
<ClInclude Include="new\net.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\message.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\blob.h">
<Filter>system</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="new\array_table.h">
<Filter>include\table</Filter>
</ClCompile>
<ClCompile Include="new\log.cpp">
<Filter>util</Filter>
</ClCompile>
<ClCompile Include="new\zoo.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\worker.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\actor.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\server.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\controller.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\communicator.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\net.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\table.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\multiverso.cpp">
<Filter>system</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="include">
<UniqueIdentifier>{befa27d3-15da-409a-a02e-fc1d9e676f80}</UniqueIdentifier>
</Filter>
<Filter Include="system">
<UniqueIdentifier>{f1d6488a-2e66-4610-8676-304c070d7b49}</UniqueIdentifier>
</Filter>
<Filter Include="util">
<UniqueIdentifier>{4e63d643-6e66-4f5c-832b-232b5a5ad239}</UniqueIdentifier>
</Filter>
<Filter Include="include\table">
<UniqueIdentifier>{eb628a56-01c9-4c87-a995-9504264c0e54}</UniqueIdentifier>
</Filter>
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="new\kv_table.h">
<Filter>include\table</Filter>
</ClInclude>
<ClInclude Include="new\multiverso.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="new\table_interface.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="new\log.h">
<Filter>util</Filter>
</ClInclude>
<ClInclude Include="new\zoo.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\worker.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\actor.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\server.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\controller.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\communicator.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\waiter.h">
<Filter>util</Filter>
</ClInclude>
<ClInclude Include="new\mt_queue.h">
<Filter>util</Filter>
</ClInclude>
<ClInclude Include="new\net.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\message.h">
<Filter>system</Filter>
</ClInclude>
<ClInclude Include="new\blob.h">
<Filter>system</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="new\array_table.h">
<Filter>include\table</Filter>
</ClCompile>
<ClCompile Include="new\log.cpp">
<Filter>util</Filter>
</ClCompile>
<ClCompile Include="new\zoo.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\worker.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\actor.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\server.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\controller.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\communicator.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\net.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\table.cpp">
<Filter>system</Filter>
</ClCompile>
<ClCompile Include="new\multiverso.cpp">
<Filter>system</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="include">
<UniqueIdentifier>{befa27d3-15da-409a-a02e-fc1d9e676f80}</UniqueIdentifier>
</Filter>
<Filter Include="system">
<UniqueIdentifier>{f1d6488a-2e66-4610-8676-304c070d7b49}</UniqueIdentifier>
</Filter>
<Filter Include="util">
<UniqueIdentifier>{4e63d643-6e66-4f5c-832b-232b5a5ad239}</UniqueIdentifier>
</Filter>
<Filter Include="include\table">
<UniqueIdentifier>{eb628a56-01c9-4c87-a995-9504264c0e54}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,10 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

Двоичные данные
next/IMultiverso/IMultiverso.opensdf

Двоичный файл не отображается.

Двоичные данные
next/IMultiverso/IMultiverso.sdf

Двоичный файл не отображается.

Просмотреть файл

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

Просмотреть файл

@ -1,10 +0,0 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

Просмотреть файл

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

Просмотреть файл

@ -1,10 +0,0 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

Просмотреть файл

@ -1,10 +0,0 @@
d:\project\imultiverso\test\x64\release\vc120.pdb
d:\project\imultiverso\test\x64\release\main.obj
d:\project\imultiverso\x64\release\test.exe
d:\project\imultiverso\x64\release\test.pdb
d:\project\imultiverso\test\x64\release\test.tlog\cl.command.1.tlog
d:\project\imultiverso\test\x64\release\test.tlog\cl.read.1.tlog
d:\project\imultiverso\test\x64\release\test.tlog\cl.write.1.tlog
d:\project\imultiverso\test\x64\release\test.tlog\link.command.1.tlog
d:\project\imultiverso\test\x64\release\test.tlog\link.read.1.tlog
d:\project\imultiverso\test\x64\release\test.tlog\link.write.1.tlog

Просмотреть файл

@ -1,5 +0,0 @@
Build started 2/2/2016 8:16:32 PM.
Build succeeded.
Time Elapsed 00:00:00.01

Просмотреть файл

@ -1,21 +0,0 @@
d:\project\imultiverso\x64\release\vc120.pdb
d:\project\imultiverso\x64\release\zoo.obj
d:\project\imultiverso\x64\release\worker.obj
d:\project\imultiverso\x64\release\static_table_impl.obj
d:\project\imultiverso\x64\release\server.obj
d:\project\imultiverso\x64\release\net.obj
d:\project\imultiverso\x64\release\message.obj
d:\project\imultiverso\x64\release\log.obj
d:\project\imultiverso\x64\release\controller.obj
d:\project\imultiverso\x64\release\communicator.obj
d:\project\imultiverso\x64\release\actor.obj
d:\project\imultiverso\x64\release\table.obj
d:\project\imultiverso\x64\release\array_table.obj
d:\project\imultiverso\x64\release\multiverso.obj
d:\project\imultiverso\x64\release\imultiverso.lib
d:\project\imultiverso\x64\release\imultiverso.tlog\cl.command.1.tlog
d:\project\imultiverso\x64\release\imultiverso.tlog\cl.read.1.tlog
d:\project\imultiverso\x64\release\imultiverso.tlog\cl.write.1.tlog
d:\project\imultiverso\x64\release\imultiverso.tlog\lib-link.read.1.tlog
d:\project\imultiverso\x64\release\imultiverso.tlog\lib-link.write.1.tlog
d:\project\imultiverso\x64\release\imultiverso.tlog\lib.command.1.tlog

Просмотреть файл

@ -1,5 +0,0 @@
Build started 2/2/2016 8:16:32 PM.
Build succeeded.
Time Elapsed 00:00:00.03

Просмотреть файл

@ -1,154 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{546681D6-495C-4AEE-BBC2-3CAEC86B5137}</ProjectGuid>
<SccProjectName>SAK</SccProjectName>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
<SccProvider>SAK</SccProvider>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Test</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)/new/;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)/x64/Release;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>IMultiverso.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{546681D6-495C-4AEE-BBC2-3CAEC86B5137}</ProjectGuid>
<SccProjectName>SAK</SccProjectName>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
<SccProvider>SAK</SccProvider>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Test</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)/new/;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)/x64/Release;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>IMultiverso.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
</Project>

262
next/IMultiverso/Test/main.cpp → next/Test/main.cpp Executable file → Normal file
Просмотреть файл

@ -1,132 +1,132 @@
#include <iostream>
#include <multiverso.h>
#include <log.h>
#include <array_table.h>
#include <kv_table.h>
#include <net.h>
using namespace multiverso;
void TestKV() {
Log::Info("Test KV map \n");
// ----------------------------------------------------------------------- //
// this is a demo of distributed hash table to show how to use the multiverso
// ----------------------------------------------------------------------- //
// 1. Start the Multiverso engine ---------------------------------------- //
MultiversoInit();
// 2. To create the shared table ----------------------------------------- //
// TODO(feiga): This table must be create at both worker and server endpoint
// simultaneously, since they should share same type and same created order
// (same order means same table id). So it's better to create them with some
// specific creator, instead of current way
// TODO(feiga): should add some if statesment
// if the node is worker, then create a worker cache table
KVWorkerTable<int, int>* dht = new KVWorkerTable<int, int>();
// if the node is server, then create a server storage table
KVServerTable<int, int>* server_dht = new KVServerTable<int, int>();
MultiversoBarrier();
// 3. User program ------------------------------------------------------- //
// all this interface is related with the KVWorkerTable
// the data structure and the interface can be both defined by users
// We also provides several common implementations
// For specific program, user-defined table may provides better performance
// access the local cache
std::unordered_map<int, int>& kv = dht->raw();
// The Get/Add are sync operation, when the function call returns, we already
// Get from server, or the server has Added the update
// Get from the server
dht->Get(0);
// Check the result. Since no one added, this should be 0
Log::Info("Get 0 from kv server: result = %d\n", kv[0]);
// Add 1 to the server
dht->Add(0, 1);
// Check the result. Since just added one, this should be 1
dht->Get(0);
Log::Info("Get 0 from kv server after add 1: result = %d\n", kv[0]);
// 4. Shutdown the Multiverso engine. ------------------------------------ //
MultiversoShutDown();
}
void TestArray() {
Log::Info("Test Array \n");
MultiversoInit();
ArrayWorker<float>* shared_array = new ArrayWorker<float>(10);
ArrayServer<float>* server_array = new ArrayServer<float>(10);
MultiversoBarrier();
Log::Info("Create tables OK\n");
std::vector<float>& vec = shared_array->raw();
shared_array->Get();
Log::Info("Get OK\n");
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
std::vector<float> delta(10);
for (int i = 0; i < 10; ++i) delta[i] = static_cast<float>(i);
shared_array->Add(delta.data(), 10);
Log::Info("Add OK\n");
shared_array->Get();
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
MultiversoShutDown();
}
void TestNet() {
NetInterface* net = NetInterface::Get();
net->Init();
char* hi = "hello, world";
if (net->rank() == 0) {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(0);
msg->set_dst(1);
msg->Push(Blob(hi, 13));
net->Send(msg);
Log::Info("rank 0 send\n");
} else if (net->rank() == 1) {
MessagePtr msg = std::make_unique<Message>();
net->Recv(&msg);
Log::Info("rank 1 recv\n");
CHECK(strcmp(msg->data()[0].data(), hi) == 0);
}
net->Finalize();
}
int main(int argc, char* argv[]) {
if (argc == 2) {
if (strcmp(argv[1], "kv") == 0) TestKV();
else if (strcmp(argv[1], "array") == 0) TestArray();
else if (strcmp(argv[1], "net") == 0) TestNet();
else CHECK(false);
} else {
TestArray();
}
return 0;
#include <iostream>
#include <multiverso.h>
#include <log.h>
#include <array_table.h>
#include <kv_table.h>
#include <net.h>
using namespace multiverso;
void TestKV() {
Log::Info("Test KV map \n");
// ----------------------------------------------------------------------- //
// this is a demo of distributed hash table to show how to use the multiverso
// ----------------------------------------------------------------------- //
// 1. Start the Multiverso engine ---------------------------------------- //
MultiversoInit();
// 2. To create the shared table ----------------------------------------- //
// TODO(feiga): This table must be create at both worker and server endpoint
// simultaneously, since they should share same type and same created order
// (same order means same table id). So it's better to create them with some
// specific creator, instead of current way
// TODO(feiga): should add some if statesment
// if the node is worker, then create a worker cache table
KVWorkerTable<int, int>* dht = new KVWorkerTable<int, int>();
// if the node is server, then create a server storage table
KVServerTable<int, int>* server_dht = new KVServerTable<int, int>();
MultiversoBarrier();
// 3. User program ------------------------------------------------------- //
// all this interface is related with the KVWorkerTable
// the data structure and the interface can be both defined by users
// We also provides several common implementations
// For specific program, user-defined table may provides better performance
// access the local cache
std::unordered_map<int, int>& kv = dht->raw();
// The Get/Add are sync operation, when the function call returns, we already
// Get from server, or the server has Added the update
// Get from the server
dht->Get(0);
// Check the result. Since no one added, this should be 0
Log::Info("Get 0 from kv server: result = %d\n", kv[0]);
// Add 1 to the server
dht->Add(0, 1);
// Check the result. Since just added one, this should be 1
dht->Get(0);
Log::Info("Get 0 from kv server after add 1: result = %d\n", kv[0]);
// 4. Shutdown the Multiverso engine. ------------------------------------ //
MultiversoShutDown();
}
void TestArray() {
Log::Info("Test Array \n");
MultiversoInit();
ArrayWorker<float>* shared_array = new ArrayWorker<float>(10);
ArrayServer<float>* server_array = new ArrayServer<float>(10);
MultiversoBarrier();
Log::Info("Create tables OK\n");
std::vector<float>& vec = shared_array->raw();
shared_array->Get();
Log::Info("Get OK\n");
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
std::vector<float> delta(10);
for (int i = 0; i < 10; ++i) delta[i] = static_cast<float>(i);
shared_array->Add(delta.data(), 10);
Log::Info("Add OK\n");
shared_array->Get();
for (int i = 0; i < 10; ++i) std::cout << vec[i] << " "; std::cout << std::endl;
MultiversoShutDown();
}
void TestNet() {
NetInterface* net = NetInterface::Get();
net->Init();
char* hi = "hello, world";
if (net->rank() == 0) {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(0);
msg->set_dst(1);
msg->Push(Blob(hi, 13));
net->Send(msg);
Log::Info("rank 0 send\n");
} else if (net->rank() == 1) {
MessagePtr msg = std::make_unique<Message>();
net->Recv(&msg);
Log::Info("rank 1 recv\n");
CHECK(strcmp(msg->data()[0].data(), hi) == 0);
}
net->Finalize();
}
int main(int argc, char* argv[]) {
if (argc == 2) {
if (strcmp(argv[1], "kv") == 0) TestKV();
else if (strcmp(argv[1], "array") == 0) TestArray();
else if (strcmp(argv[1], "net") == 0) TestNet();
else CHECK(false);
} else {
TestArray();
}
return 0;
}

Просмотреть файл

@ -1,96 +0,0 @@
#ifndef MULTIVERSO_AGGREGATOR_H_
#define MULTIVERSO_AGGREGATOR_H_
/*!
* \brief Defines aggregator
*/
#include <vector>
#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include "meta.h"
namespace zmq
{
class socket_t;
}
namespace multiverso
{
class Table;
/*!
* \brief Aggregator is responsble for collecting, aggregating, storing
* and sending local updates.
*/
class IAggregator
{
public:
/*!
* \brief Construct an aggregator.
* \param num_threads number of background aggregator threads
* \param num_trainers number of trainer thread
*/
virtual ~IAggregator() = default;
/*!
* \brief Create table for local updates aggregation
* \param table_id Table identity
* \param rows Number of rows
* \param cols Number of columns
* \param type Element type
* \param default_format Default row format
* \param memory_pool_size Memory pool size. When creating rows,
* the table will reuse the memory pool if available.
*/
void CreateTable(integer_t table_id, integer_t rows, integer_t cols,
Type type, Format default_format, int64_t memory_pool_size = 0);
/*!
* \brief Configures a row of aggregation tables
* \param table_id Table id
* \param row_id Row id
* \param format Row format.
* \param capacity The initial maximal number of elements the row
* stores, it is fixed for DENSE row (array), and can be
* auto-growed for SPARSE row (hash table).
* \return Returns 0 on success, or -1 with error.
*/
int SetAggregatorRow(integer_t table_id, integer_t row_id,
Format format, integer_t capacity);
/*!
* \brief Add to
* \param trainer trainer id
* \param table table id
* \param row row id
* \param col col id
* \param delta pointer to delta
*/
virtual void Add(int trainer, integer_t table,
integer_t row, integer_t col, void* delta) = 0;
virtual void BatchAdd(int trainer, integer_t table,
integer_t row, void* row_delta) = 0;
virtual void Flush(int trainer) = 0;
virtual void Clock(int trainer) = 0;
/*! \brief Wait until all client finish sync up */
virtual void Wait() {}
static IAggregator* CreateAggregator(
int num_aggregators, int num_trainers);
protected:
std::vector<Table*> tables_; // buffer to store update
/*! \brief Send local updates */
void Send(int id, zmq::socket_t* socket, int num_threads = 1);
};
}
#endif // MULTIVERSO_AGGREGATOR_H_

Просмотреть файл

@ -1,54 +0,0 @@
#ifndef MULTIVERSO_BARRIER_H_
#define MULTIVERSO_BARRIER_H_
/*!
* \file barrier.h
* \brief Defines Barrier for multithreading.
*/
#include <thread>
#include <atomic>
#include <condition_variable>
namespace multiverso
{
/*!
* \brief A synchronization barrier, which enables multiple threads
* to wait until all threads have all reached a particular
* point of execution before any thread continues.
*/
class Barrier
{
public:
/*!
* \brief Creates a Barrier instance.
* \param num_threads Number of threads joining the barrier
*/
explicit Barrier(int num_threads);
/*!
* \brief Resets the number of threas (barrier size).
* \param num_threads New barrier size
* \return 0 on success, -1 if num_threads is invalid (not greater than 0)
*/
int ResetNumThreads(int num_threads);
/*!
* \brief Synchronize participating threads at the barrier.
* \return true if current thread is the last one, false otherwise
*/
bool Wait();
private:
int barrier_size_; // number of threads barrierred by Wait()
int num_in_waiting_; // number of threads in waiting
std::condition_variable cond_;
std::mutex mutex_;
// No copying allowed
Barrier(const Barrier&);
void operator=(const Barrier&);
};
}
#endif // MULTIVERSO_BARRIER_H_

Просмотреть файл

@ -1,105 +0,0 @@
#ifndef MULTIVERSO_COMMUNICATOR_H_
#define MULTIVERSO_COMMUNICATOR_H_
/*!
* \file communicator.h
* \brief Define the Communicator class
* \author feiyan
*/
#include <string>
#include <vector>
#include <thread>
#include "zmq.hpp"
#include "meta.h"
namespace multiverso
{
struct Config;
class Server;
/*!
* \brief The Communicator class is responsible for receiving messages from
* internal threads or external processes and forward them to
* appropriate destinations.
*/
class Communicator
{
public:
/*!
* \brief Creates a Communicator object and starts a background
* communication thread.
* \param config Configuration information
* \param argc Number of commandline arguments, for initializing MPI
* \param argv Commandline arguments, for initializing MPI
*/
Communicator(const Config &config, int *argc, char **argv[]);
/*! \brief Cleans up and closes the communicator (thread). */
~Communicator();
/*!
* \brief Registers the worker process to the master server, gets the
* assigned process rank and global information.
* \param socket The main thread socket connecting to the communicator.
* \param config Multiverso configuration.
* \param num_trainers Number of local trainers.
* \return Returns the received register information.
*/
RegisterInfo Register(zmq::socket_t *socket, const Config &config,
int num_trainers);
///*!
// * \brief Returns MPI rank of the process in MPI version. Undefined
// * behavior in non-MPI version.
// */
//int MPIRank();
///*!
// * \brief Returns the number of processes in MPI version. Undefined
// * behavior in non-MPI version.
// */
//int MPISize();
/*!
* \brief Sets a flag of whether finalizing MPI while closing the
* Communicator. It is true by default.
*/
void SetMPIFinalize(bool finalize) { mpi_finalize_ = finalize; }
///*! \brief Sets the process rank.*/
//void SetProcRank(int proc_rank) { proc_rank_ = proc_rank; }
/*!
* \brief Returns a ZMQ DEALER socket for internal working threads
* connecting to the ROUTER socket in the Communicator.
*/
zmq::socket_t *CreateSocket();
///*!
// * \brief Returns the number of connected servers in ZMQ version.
// * Undefined behavior in MPI version.
// */
//int ServerCount() { return static_cast<int>(dealers_.size()); }
private:
void StartThread(std::string server_endpoint_file); // comm thread method
void Init(std::string server_endpoint_file); // initialization
void Clear(); // clean up
// area of member variables ------------------------------------------/
zmq::socket_t *router_; // socket for receiving working thread messages
std::vector<zmq::socket_t*> dealers_; // socket for connecting to servers
zmq::pollitem_t *poll_items_;
int poll_count_;
RegisterInfo reg_info_;
//int proc_rank_; // process rank
bool mpi_finalize_; // finalize MPI while closing the communicator if true
bool is_working_; // communication thread keeps working while it is true
std::thread comm_thread_;
Server *server_;
// No copying allowed
Communicator(const Communicator&);
void operator=(const Communicator&);
};
}
#endif // MULTIVERSO_COMMUNICATOR_H_

Просмотреть файл

@ -1,32 +0,0 @@
#ifndef MULTIVERSO_DATA_BLOCK_H_
#define MULTIVERSO_DATA_BLOCK_H_
#include <atomic>
namespace multiverso
{
enum class DataBlockType : int
{
Train = 0,
Test = 1,
BeginClock = 2,
EndClock = 3
};
class DataBlockBase
{
public:
DataBlockBase();
explicit DataBlockBase(DataBlockType type);
DataBlockType Type() const { return type_; }
void SetType(DataBlockType type) { type_ = type; }
void IncreaseCount(int delta) { count_ += delta; }
bool IsDone() { return count_ == 0; }
private:
DataBlockType type_;
std::atomic<int> count_;
};
}
#endif // MULTIVERSO_DATA_BLOCK_H_

Просмотреть файл

@ -1,68 +0,0 @@
#ifndef MULTIVERSO_DELTA_POOL_H_
#define MULTIVERSO_DELTA_POOL_H_
/*!
* \file delta_pool.h
* \brief Defines DeltaPool data structure
*/
#include "meta.h"
#include "mt_queue.h"
#include <memory>
namespace multiverso
{
/*!
* \brief DeltaPool
*/
class DeltaPool
{
public:
/*! \brief Constructs a DeltaPool */
explicit DeltaPool(int num_producer, int capacity = kDeltaPoolCapacity);
~DeltaPool();
/*!
* \brief Push a delta quadruple by an adaptor
* \param trainer trainer id
* \param table table id
* \param row row id
* \param col col id
* \param delta pointer to the pushed value
*/
void Push(int trainer, integer_t table,
integer_t row, integer_t col, void* delta, int size);
/*!
* \brief Pop a delta quadruple by an aggregator
* \param table returned table id
* \param row returned row id
* \param col returned col id
* \param delta returned pointer to the pop value
* \return true if Pop success, false if deltapool exit
*/
bool Pop(integer_t& table,
integer_t& row, integer_t& col, void*& delta);
/*! \brief Exit the deltapool, awake all threads wait if necessary */
void Exit();
private:
struct Entity;
class EntityArray;
typedef std::unique_ptr<EntityArray> Pointer;
bool NeedFlush(int row);
/*! \brief queue to cache available entity arrays */
MtQueueMove<Pointer> empty_queue_;
/*! \brief queue to store full entity arrays */
MtQueueMove<Pointer> full_queue_;
/*! \brief Each procucer has a pointer */
std::vector<Pointer> producer_set_;
/*! \brief consumer pointer*/
Pointer consumer_;
// No copying allowed
DeltaPool(const DeltaPool&);
void operator=(const DeltaPool&);
};
}
#endif // MULTIVERSO_DELTA_POOL_H_

Просмотреть файл

@ -1,168 +0,0 @@
#ifndef MULTIVERSO_DOUBLE_BUFFER_H_
#define MULTIVERSO_DOUBLE_BUFFER_H_
/*!
* \brief Defines DoubleBuffer
* \author feiga
*/
#include <vector>
#include <mutex>
#include <condition_variable>
#include <memory>
#include "barrier.h"
namespace multiverso
{
/*!
* \brief A concurrency DoubleBuffer shared by multiple worker threads and
* one IO thread. All threads should call Start(thread_id) method
* before access and call End(thread_id) after access. Any operation
* outside the range between Start and End are undefined.
* \tparam Container underlying buffer type that DoubleBuffer holds
*/
template<class Container>
class DoubleBuffer
{
public:
/*!
* \brief Constructs a DoubleBuffer
* \param num_threads number of worker threads
* \param reader_buffer pointer to one buffer
* \param writer_buffer pointer to another buffer
*/
DoubleBuffer(int num_threads, Container* reader_buffer,
Container* writer_buffer);
/*! \brief Exit the DoubleBuffer, awake all threads blocked */
void Exit();
/*!
* \brief Start access of DoubleBuffer
* \param thread_id
*/
void Start(int thread_id);
/*!
* \brief End access of DoubleBuffer
* \param thread_id
*/
void End(int thread_id);
/*!
* \brief Get the worker buffer, only worker threads shoud call this.
* Must be called between Start and End
* \return reference of underlying buffer
*/
Container& WorkerBuffer();
/*!
* \brief Get the IO buffer, only IO threads should call this
* Must be called between Start and End
* \return reference underlying buffer
*/
Container& IOBuffer();
private:
/*! \brief num of total threads that have access to this buffer */
int num_threads_;
/*! \brief underlying reader buffer */
Container* reader_buffer_;
/*! \brief underlying writer buffer */
Container* writer_buffer_;
std::vector<bool> ready_;
std::mutex mutex_;
std::condition_variable condition_;
bool exit_;
int counter_;
// No copying allowed
DoubleBuffer(const DoubleBuffer&);
void operator=(const DoubleBuffer&);
};
/*!
* \brief RAII class for Buffer access
* \tparam Buf, DoubleBuffer<T> type, should have method Start and End
*/
template<class Buf>
class BufferGuard
{
public:
BufferGuard(Buf& buffer, int thread_id);
~BufferGuard();
private:
Buf& buffer_;
int thread_id_;
};
template<class Container>
DoubleBuffer<Container>::DoubleBuffer(int num_threads,
Container* reader_buffer, Container* writer_buffer)
: num_threads_(num_threads + 1), counter_(num_threads)
{
reader_buffer_ = reader_buffer;
writer_buffer_ = writer_buffer;
ready_.resize(num_threads_); // plus one for IO thread.
ready_[0] = true; // id 0 is io thread by default.
exit_ = false;
}
template<class Container>
void DoubleBuffer<Container>::Exit()
{
std::unique_lock<std::mutex> lock(mutex_);
exit_ = true;
condition_.notify_one();
}
template<class Container>
void DoubleBuffer<Container>::Start(int thread_id)
{
std::unique_lock<std::mutex> lock(mutex_);
condition_.wait(lock,
[&](){ return ready_[thread_id] == true || exit_ == true; });
}
template<class Container>
void DoubleBuffer<Container>::End(int thread_id)
{
std::unique_lock<std::mutex> lock(mutex_);
ready_[thread_id] = false;
if (++counter_ == num_threads_)
{
counter_ = 0;
std::swap(reader_buffer_, writer_buffer_);
std::fill(ready_.begin(), ready_.end(), true);
condition_.notify_all();
}
}
template<class Container>
Container& DoubleBuffer<Container>::WorkerBuffer()
{
return *reader_buffer_;
}
template<class Container>
Container& DoubleBuffer<Container>::IOBuffer()
{
return *writer_buffer_;
}
template<class Buf>
BufferGuard<Buf>::BufferGuard(Buf& buffer, int thread_id)
: buffer_(buffer), thread_id_(thread_id)
{
buffer_.Start(thread_id_);
}
template<class Buf>
BufferGuard<Buf>::~BufferGuard()
{
buffer_.End(thread_id_);
}
}
#endif //MULTIVERSO_DOUBLE_BUFFER_H_

Просмотреть файл

@ -1,45 +0,0 @@
#ifndef MULTIVERSO_ENDPOINT_LIST_H_
#define MULTIVERSO_ENDPOINT_LIST_H_
/*
* \file endpoint_list.h
* \brief Defines the EndpointList class.
* \author feiyan
*/
#include <string>
#include <vector>
namespace multiverso
{
/*!
* \brief The EndpointList class is a container for storing server ZMQ
* socket endpoints. It reads the information from a simple
* configuration file. The file contains multiple lines each for a
* server with the format "server_id ip:port"
*/
class EndpointList
{
public:
/*!
* \brief Constructs an EndpointList instance and reads the endpoint
* configuraion from the file.
* \param filename The filename of the server ZMQ endpoint configuration.
*/
explicit EndpointList(std::string filename);
~EndpointList();
/*!
* \brief Returns the endpoint of a specified server id. Returns empty
* string "" if invalid.
*/
std::string GetEndpoint(int id);
/*! \brief Returns the number of endpoints (servers). */
int Size() { return static_cast<int>(endpoints_.size()); }
private:
std::vector<std::string> endpoints_;
};
}
#endif // MULTIVERSO_ENDPOINT_LIST_H_

Просмотреть файл

@ -1,110 +0,0 @@
#ifndef MULTIVERSO_HDFS_FILE_SYS_H_
#define MULTIVERSO_HDFS_FILE_SYS_H_
/*!
* \file local_file_sys.h
* \brief The implement of hdfs io interface.
*/
#include "io.h"
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <cassert>
#include <algorithm>
extern "C"
{
#include <hdfs.h>
}
namespace multiverso
{
class HDFSStream : public Stream
{
public:
HDFSStream(hdfsFS fs, hdfsFile fp, std::string path);
~HDFSStream(void);
/*!
* \brief write data to a file
* \param buf pointer to a memory buffer
* \param size data size
*/
virtual void Write(const void *buf, size_t size) override;
/*!
* \brief read data from Stream
* \param buf pointer to a memory buffer
* \param size the size of buf
*/
virtual size_t Read(void *buf, size_t size) override;
/*!
* \brief move the position point to seekOrigin + offset
* \param offset the offset(bytes number) to change the position point
* \param seekOrigin the reference position
*/
virtual void Seek(size_t offset, SeekOrigin seekOrigin) override;
/*!
* \brief flush local buffer
*/
virtual void Flush() override;
private:
hdfsFS fs_;
hdfsFile fp_;
std::string path_;
};
class HDFSFileSystem : public FileSystem
{
public:
explicit HDFSFileSystem(const std::string host);
virtual ~HDFSFileSystem(void);
/*!
* \brief create a Stream
* \param path the path of the file
* \param mode "w" - create an empty file to store data;
* "a" - open the file to append data to it
* "r" - open the file to read
* \return the Stream which is used to write or read data
*/
virtual Stream *Open(const std::string path,
const char *mode) override;
virtual void CreateDirectory(const std::string path) override;
/*!
* \brief check if the path exists
* \param path the file or directory
*/
virtual bool Exists(const std::string path) override;
/*!
* \brief delete the file or directory
* \param path the file or directory
*/
virtual void Delete(const std::string path) override;
virtual FileInfo*GetPathInfo(const std::string path) override;
virtual void Rename(const std::string old_path, const std::string new_path) override;
virtual void Copy(const std::string src, const std::string dst) override;
virtual void ListDirectory(const std::string path, std::vector<FileInfo*> &files) override;
virtual void Close() override;
private:
std::string namenode_;
hdfsFS fs_;
};
}
#endif // MULTIVERSO_HDFS_FILE_SYS_H_

Просмотреть файл

@ -1,153 +0,0 @@
#ifndef MULTIVERSO_IO_H_
#define MULTIVERSO_IO_H_
/*!
* \file io.h
* \brief Defines io interface.
*/
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <cassert>
#include <string>
#include <vector>
#include <map>
#include "log.h"
namespace multiverso
{
/*!
* \brief the reference positon for seeking
* the position point of Stream
*/
enum class SeekOrigin : int
{
kBegin = 0,
kCurrent = 1,
kEnd = 2
};
class Stream
{
public:
/*!
* \brief write data to a file
* \param buf pointer to a memory buffer
* \param size data size
*/
virtual void Write(const void *buf, size_t size) = 0;
/*!
* \brief read data from Stream
* \param buf pointer to a memory buffer
* \param size the size of buf
*/
virtual size_t Read(void *buf, size_t size)= 0;
/*!
* \brief move the position point to seekOrigin + offset
* \param offset the offset(bytes number) to change the position point
* \param seekOrigin the reference position
*/
virtual void Seek(size_t offset, SeekOrigin seekOrigin) = 0;
/*!
* \brief flush local buffer
*/
virtual void Flush() = 0;
};
enum class FileType : int
{
kFile = 0,
kDirectory = 1
};
struct FileInfo
{
FileInfo() : size(0), type(FileType::kFile) {}
std::string path;
size_t size;
FileType type;
};
class FileSystem
{
public:
/*!
* /brief get an instance of FileSystem
* /param type the type of FileSystem
* "hdfs" or "file"
* /param host for "hdfs", host is address of namenode
* for "file", host can be empty
*/
static FileSystem *GetInstance(const std::string type,
const std::string host);
/*!
* \brief create a Stream
* \param path the path of the file
* \param mode "w" - create an empty file to store data;
* "a" - open the file to append data to it
* "r" - open the file to read
* \return the Stream which is used to write or read data
*/
virtual Stream *Open(const std::string path,
const char *mode) = 0;
virtual void CreateDirectory(const std::string path) = 0;
/*!
* \brief check if the path exists
* \param path the file or directory
*/
virtual bool Exists(const std::string path) = 0;
/*!
* \brief delete the file or directory
* \param path the file or directory
*/
virtual void Delete(const std::string path) = 0;
virtual FileInfo *GetPathInfo(const std::string path) = 0;
virtual void Rename(const std::string old_path, const std::string new_path) = 0;
virtual void Copy(const std::string src, const std::string dst) = 0;
virtual void ListDirectory(const std::string path, std::vector<FileInfo*> &files) = 0;
virtual void Close() = 0;
~FileSystem();
protected:
static std::map<std::pair<std::string, std::string>, FileSystem *>instances_;
FileSystem() {}
};
class TextReader
{
public:
TextReader(Stream *stream, size_t buf_size);
size_t GetLine(char *line);
~TextReader();
private:
size_t LoadBuffer();
char * buf_;
size_t pos_, buf_size_, length_;
Stream *stream_;
};
}
#endif // MULTIVERSO_IO_H_

Просмотреть файл

@ -1,97 +0,0 @@
#ifndef MULTIVERSO_LOCAL_FILE_SYS_H_
#define MULTIVERSO_LOCAL_FILE_SYS_H_
/*!
* \file local_file_sys.h
* \brief the implement of local io interface.
*/
#include "io.h"
namespace multiverso
{
class LocalStream : public Stream
{
public:
explicit LocalStream(FILE * fp, std::string path);
/*!
* \brief write data to a file
* \param buf pointer to a memory buffer
* \param size data size
*/
virtual void Write(const void *buf, size_t size) override;
/*!
* \brief read data from Stream
* \param buf pointer to a memory buffer
* \param size the size of buf
*/
virtual size_t Read(void *buf, size_t size) override;
/*!
* \brief move the position point to seekOrigin + offset
* \param offset the offset(bytes number) to change the position point
* \param seekOrigin the reference position
*/
virtual void Seek(size_t offset, SeekOrigin seekOrigin) override;
/*!
* \brief flush local buffer
*/
virtual void Flush() override;
~LocalStream();
private:
FILE *fp_;
std::string path_;
};
class LocalFileSystem : public FileSystem
{
public:
LocalFileSystem(std::string host);
~LocalFileSystem(void);
/*!
* \brief create a Stream
* \param path the path of the file
* \param mode "w" - create an empty file to store data;
* "a" - open the file to append data to it
* "r" - open the file to read
* \return the Stream which is used to write or read data
*/
virtual Stream* Open(const std::string path,
const char *mode) override;
virtual void CreateDirectory(const std::string path) override;
/*!
* \brief check if the path exists
* \param path the file or directory
*/
virtual bool Exists(const std::string path) override;
/*!
* \brief delete the file or directory
* \param path the file or directory
*/
virtual void Delete(const std::string path) override;
virtual FileInfo* GetPathInfo(const std::string path) override;
virtual void Rename(const std::string old_path, const std::string new_path) override;
virtual void Copy(const std::string src, const std::string dst) override;
virtual void ListDirectory(const std::string path, std::vector<FileInfo*> & files) override;
virtual void Close() override;
private:
std::string host_;
};
}
#endif // MULTIVERSO_LOCAL_FILE_SYS_H_

Просмотреть файл

@ -1,57 +0,0 @@
#ifndef MULTIVERSO_LOCK_H_
#define MULTIVERSO_LOCK_H_
/*!
* \file lock.h
* \brief Defines class LockManager for contentions in multi-threading programs.
*/
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <mutex>
#endif
#include <vector>
namespace multiverso
{
/*!
* \brief The class Mutex is a system dependent lock wrapper. For Windows
* system, it wraps a CRITICAL_SECTION object for high efficiency;
* otherwise it wraps a C++ standard mutex object.
*/
class Mutex;
/*!
* \brief The class LockManager is a Mutex container providing locking
* features.
*/
class LockManager
{
public:
/*!
* \brief Creates a LockManager with specific number of Mutex objects.
* \param num_lock Number of Mutex objects. Undefined behavior if
* num_lock <= 0
*/
explicit LockManager(int num_lock);
~LockManager();
/*! \brief Locks the Mutex object with order id % lock_num. */
void Lock(int id);
/*! \brief Unlocks the Mutex object with order id % lock_num. */
void Unlock(int id);
/*! \brief Returns the number of Mutex objects. */
int Size();
private:
std::vector<Mutex> locks_;
// No copying allowed
LockManager(const LockManager&);
void operator=(const LockManager&);
};
}
#endif // MULTIVERSO_LOCK_H_

Просмотреть файл

@ -1,143 +0,0 @@
#ifndef MULTIVERSO_LOG_H_
#define MULTIVERSO_LOG_H_
/*!
* \file log.h
* \brief Provides simple logging tools.
*/
#include <fstream>
#include <string>
namespace multiverso
{
/*!
* \brief A enumeration type of log message levels. The values are ordered:
* Debug < Info < Error < Fatal.
*/
enum class LogLevel : int
{
Debug = 0,
Info = 1,
Error = 2,
Fatal = 3
};
/*!
* \brief The Logger class is responsible for writing log messages into
* standard output or log file.
*/
class Logger
{
// Enable the static Log class to call the private method.
friend class Log;
public:
/*!
* \brief Creates an instance of Logger class. By default, the log
* messages will be written to standard output with minimal
* level of INFO. Users are able to further set the log file or
* log level with corresponding methods.
* \param level Minimal log level, Info by default.
*/
explicit Logger(LogLevel level = LogLevel::Info);
/*!
* \brief Creates an instance of Logger class by specifying log file
* and log level. The log message will be written to both STDOUT
* and file (if created successfully).
* \param filename Log file name
* \param level Minimal log level
*/
explicit Logger(std::string filename, LogLevel level = LogLevel::Info);
~Logger();
/*!
* \brief Resets the log file.
* \param filename The new log filename. If it is empty, the Logger
* will close current log file (if it exists).
* \return Returns -1 if the filename is not empty but failed on
* creating the log file, or 0 will be returned otherwise.
*/
int ResetLogFile(std::string filename);
/*!
* \brief Resets the log level.
* \param level The new log level.
*/
void ResetLogLevel(LogLevel level) { level_ = level; }
/*!
* \brief Resets the option of whether kill the process when fatal
* error occurs. By defualt the option is false.
*/
void ResetKillFatal(bool is_kill_fatal) { is_kill_fatal_ = is_kill_fatal; }
/*!
* \brief C style formatted method for writing log messages. A message
* is with the following format: [LEVEL] [TIME] message
* \param level The log level of this message.
* \param format The C format string.
* \param ... Output items.
*/
void Write(LogLevel level, const char *format, ...);
void Debug(const char *format, ...);
void Info(const char *format, ...);
void Error(const char *format, ...);
void Fatal(const char *format, ...);
private:
void Write(LogLevel level, const char *format, va_list &val);
void CloseLogFile();
// Returns current system time as a string.
std::string GetSystemTime();
// Returns the string of a log level.
std::string GetLevelStr(LogLevel level);
std::FILE *file_; // A file pointer to the log file.
LogLevel level_; // Only the message not less than level_ will be outputed.
bool is_kill_fatal_; // If kill the process when fatal error occurs.
// No copying allowed
Logger(const Logger&);
void operator=(const Logger&);
};
/*!
* \brief The Log class is a static wrapper of a global Logger instance in
* the scope of a process. Users can write logging messages easily
* with the static methods.
*/
class Log
{
public:
/*!
* \brief Resets the log file. The logger will write messages to the
* log file if it exists in addition to the STDOUT by default.
* \param filename The log filename. If it is empty, the logger will
* close the current log file (if it exists) and only output to
* STDOUT.
* \return -1 if fail on creating the log file, or 0 otherwise.
*/
static int ResetLogFile(std::string filename);
/*!
* \brief Resets the minimal log level. It is INFO by default.
* \param level The new minimal log level.
*/
static void ResetLogLevel(LogLevel level);
/*!
* \brief Resets the option of whether kill the process when fatal
* error occurs. By defualt the option is false.
*/
static void ResetKillFatal(bool is_kill_fatal);
/*! \brief The C formatted methods of writing the messages. */
static void Write(LogLevel level, const char *format, ...);
static void Debug(const char *format, ...);
static void Info(const char *format, ...);
static void Error(const char *format, ...);
static void Fatal(const char *format, ...);
private:
static Logger logger_;
};
}
#endif // MULTIVERSO_LOG_H_

Просмотреть файл

@ -1,160 +0,0 @@
#ifndef MULTIVERSO_META_H_
#define MULTIVERSO_META_H_
/*!
* \file meta.h
* \brief Includes some basic options and configurations.
* \author feiyan, feiga
*/
#include <string>
namespace multiverso
{
/*!
* \brief If defined the _MPI_VERSION_ macro, the communication rountine will
* be compiled with MPI facilities, or ZMQ facilities will be used for
* inter-process communication.
*/
#define _MPI_VERSION_
#define _MULTIVERSO_DEBUG_
/*!
* \brief Defines the index type, could be 32-bit integer (int)
* or 64-bit integer (e.g. long long).
*/
typedef int integer_t;
/*!
* \brief A very small number for comparision. Two values are regarded as
* identical if their difference is within this gap.
*/
const double kEPS = 1e-9;
/*!
* \brief Maximum data block size. An instance of MsgPack should be at
* most around this size.
*/
const int kMaxMsgSize = 1 << 25; // 32 M
/*! \brief Reserved size for Delta Array */
const int kDeltaArraySize = 512 * 1024; // 64 K
/*! \brief Default size for Delta Pool */
const int kDeltaPoolCapacity = 1024;
/*!
* \brief Row (data storage) format.
* - DENSE: data will be stored with array;
* - SPARSE: data will be stored with hash table.
*/
enum class Format : int
{
Dense = 0,
Sparse = 1
};
/*! \brief Element type. */
enum class Type : int
{
Int = 0, ///< int: 32-bit integer
LongLong = 1, ///< long long: 64-bit integer
Float = 2, ///< float: 32-bit float
Double = 3 ///< double: 64-bit float
};
/*!
* \brief DeltaType defines special type of Delta, which is the
* communication entity between workers and aggregators.
*/
enum class DeltaType : int
{
Flush = -1, ///< flush: flush the cached updates to server
Clock = -2 ///< clock: clock with other nodes
};
/*! \brief Defines message types. */
enum class MsgType : int
{
// register message when initializing
Register = 1,
ReplyRegister = -1,
// close message at the end
Close = 2,
ReplyClose = -2,
// server table configuration messages
CreateTable = 3,
SetRow = 4,
// add delta to the servers
Add = 5,
ReplyAdd = -5, // QUESTION: is it necessary to have ReplyAdd option?
// clock message for synchronization
Clock = 6,
ReplyClock = -6,
// global inter-process barrier
Barrier = 7,
ReplyBarrier = -7,
// parameter request messages
Get = 8,
ReplyGet = -8,
EndTrain = 9
};
/*!
* \brief A enumeration class of lock options.
*/
enum class LockOption : int
{
Immutable = 0, // the threads do not write and there is no contention
LockFree = 1, // there is no lock for thread contention
Locked = 2 // normal lock for thread contention
};
/*
* \brief A simple data structure for passing the configuration parapmeters
* to Multiverso.
*/
struct Config
{
public:
Config()
{
num_servers = 0; // all process are servers
num_aggregator = 1;
num_trainers = 1;
max_delay = 0;
num_lock = 100;
lock_option = LockOption::Immutable;
is_pipeline = true;
server_endpoint_file = "";
}
/*
* \brief Number of servers, only applied under MPI communication mode.
* If it is not greater than 0 or greater than the number of
* processes, all processes will have a server.
*/
int num_servers;
int num_aggregator; ///< Number of aggregation threads.
int num_trainers; ///< Number of local trainer threads.
int max_delay; ///< the delay bound (max staleness)
int num_lock; ///< Number of locks in Locked option
LockOption lock_option; ///< Lock option
/// Whether overlapping the communication and computation
bool is_pipeline;
/// server ZMQ socket endpoint file in MPI-free version
std::string server_endpoint_file;
};
struct RegisterInfo
{
int proc_rank; // current process rank
int proc_count; // number of worker processes
int server_count; // number of servers
int total_trainer_count; // global number of trainers
};
}
#endif // MULTIVERSO_META_H_

Просмотреть файл

@ -1,74 +0,0 @@
#ifndef MULTIVERSO_MPI_UTIL_H_
#define MULTIVERSO_MPI_UTIL_H_
/*!
* \file mpi_util.h
* \brief Wraps the MPI facilities.
* \author feiyan
*/
#include <queue>
#include <memory>
#if defined (_MPI_VERSION_)
#include <mpi.h>
#endif
namespace multiverso
{
// MPI receive and send buffer size, for safe, one message should be at
// most around half of this size, i.e. 32 MB
const int kMPIBufferSize = 1 << 26; // 64 MB
class MsgPack;
/*!
* \brief The class MPIUtil provides the static method of using MPI
* facilities.
*/
class MPIUtil
{
public:
/*!
* \brief Initializes MPI environment.
* \param argc Number of commandline arguments
* \param argv Commandline arguments
*/
static void Init(int *argc, char **argv[]);
/*! \brief Finalizes MPI environment. */
static void Close();
/*! \brief Returns the MPI rank of current process. */
static int MPIRank() { return mpi_rank_; }
/*! \brief Returns the number of processes. */
static int MPISize() { return mpi_size_; }
static std::shared_ptr<MsgPack>ProbeAndRecv();
/*! \brief Tests if there message received and returns it, or NULL. */
//static std::shared_ptr<MsgPack> MPIProbe();
/*! \brief Sends the message with MPI. Actually the message (if not
* NULL) will be pushed into the send queue and MPI will try to
* send one in the queue when call the method once. So if you
* call Send(nullptr), the MPI will try to send one message in
* the queue (like flush but only try to send one)
*/
static void Send(std::shared_ptr<MsgPack> msg_pack);
/*! \brief Returns the size of send queue. */
static int SendQueueSize() { return static_cast<int>(send_queue_.size()); }
private:
static int mpi_size_;
static int mpi_rank_;
static std::queue<std::shared_ptr<MsgPack>> send_queue_;
#if defined (_MPI_VERSION_)
static char recv_buffer_[kMPIBufferSize];
static MPI_Request recv_request_;
static char send_buffer_[kMPIBufferSize];
static MPI_Request send_request_;
#endif
};
}
#endif // MULTIVERSO_MPI_UTIL_H_

Просмотреть файл

@ -1,122 +0,0 @@
#ifndef MULTIVERSO_MSG_PACK_H_
#define MULTIVERSO_MSG_PACK_H_
/*!
* \file msg_pack.h
* \brief Defines the MsgPack class.
* \author: feiyan
*/
#include <vector>
#include "meta.h"
namespace zmq
{
class message_t;
class socket_t;
}
namespace multiverso
{
/*!
* \brief The enumeration class MsgArrow defines two orientations of
* a message package (MsgPack).
*/
enum class MsgArrow : int
{
Worker2Server = 0, // worker -> server
Server2Worker = 1 // server -> worker
};
/*!
* \brief The class MsgPack is a wrapper (container) of ZMQ multiple message.
* In addition to address messages and delimiter message (empty
* message), the first data message (indexed with 0) is a header
* including the basic information of message type and message arrow.
* The following are user customized data message (if there is any).
*/
class MsgPack
{
public:
/*!\brief Creates an empty MsgPack.*/
MsgPack();
/*!
* \brief Creates a MsgPack with header information.
* \param type Message type
* \param arrow Message arrow
* \param src Source id, worker processor rank or server id dependently
* \param dst Destination id, server id or processor rank dependently
*/
MsgPack(MsgType type, MsgArrow arrow, int src, int dst);
/*!
* \brief Gets multiple messages from the socket and wraps them in the
* MsgPack.
* \param socket A ZMQ socket getting the messages from
*/
explicit MsgPack(zmq::socket_t *socket);
/*!
* \brief Deserializes a block of binary data as ZMQ messages and
* composes a MsgPack.
* \param buffer Pointer to the input memory block
* \param size Size of the memory block (in bytes)
*/
MsgPack(char *buffer, int size);
~MsgPack();
/*!
* \brief Pushes a ZMQ message into the MsgPack.
* \param msg A pointer to a ZMQ message.
*/
void Push(zmq::message_t *msg);
/*!
* \brief Gets the header information
* \param type Message type
* \param arrow Message arrow
* \param src Source id
* \param dst Destination id
*/
void GetHeaderInfo(MsgType *type, MsgArrow *arrow, int *src, int *dst);
/*!
* \brief Sends the messages with the socket.
* \param socket A ZMQ socket for sending the messages
*/
void Send(zmq::socket_t *socket);
/*!
* \brief Returns a pointer to a specific message. (The header message
* is indexed 0) and following are user data message.
* \param idx Message index.
*/
zmq::message_t *GetMsg(int idx) { return messages_[start_ + idx]; }
/*! \brief Returns the number of data messages. */
int Size() { return static_cast<int>(messages_.size() - start_); }
/*!
* \brief Creates a MsgPack replying to this MsgPack, the router
* addresses (and the delimiter) will be copied to the new
* MsgPack and the header information will be constructed
* accordingly.
*/
MsgPack *CreateReplyMsgPack();
/*!
* \brief Serializes the messages into a binary block.
* \param buffer Pointer to the output block
* \param size of the serialized data block
*/
void Serialize(char *buffer, int *size);
private:
int start_; // index to the header message
std::vector<zmq::message_t*> messages_;
// No copying allowed
MsgPack(const MsgPack&);
void operator=(const MsgPack&);
};
}
#endif // MULTIVERSO_MSG_PACK_H_

Просмотреть файл

@ -1,134 +0,0 @@
#ifndef MULTIVERSO_MT_QUEUE_H_
#define MULTIVERSO_MT_QUEUE_H_
/*!
* \brief Defines a thread safe queue
*/
#include <queue>
#include <mutex>
#include <condition_variable>
namespace multiverso
{
/*!
* \brief A thread safe queue support multithread push and pop concurrently
* The queue is based on move semantics.
*/
template<typename T>
class MtQueueMove {
public:
/*! \brief Constructor */
MtQueueMove() : exit_(false) {}
/*!
* \brief Push an element into the queue. the function is based on
* move semantics. After you pushed, the item would be an
* uninitialized variable.
* \param item item to be pushed
*/
void Push(T& item);
/*!
* \brief Pop an element from the queue, if the queue is empty, thread
* call pop would be blocked
* \param result the returned result
* \return true when pop sucessfully; false when the queue is exited
*/
bool Pop(T& result);
/*!
* \brief Get the front element from the queue, if the queue is empty,
* threat who call front would be blocked. Not move semantics.
* \param result the returned result
* \return true when pop sucessfully; false when the queue is exited
*/
bool Front(T& result);
/*!
* \brief Gets the number of elements in the queue
* \return size of queue
*/
int Size() const;
/*!
* \brief Whether queue is empty or not
* \return true if queue is empty; false otherwise
*/
bool Empty() const;
/*! \brief Exit queue, awake all threads blocked by the queue */
void Exit();
private:
/*! the underlying container of queue */
std::queue<T> buffer_;
mutable std::mutex mutex_;
std::condition_variable empty_condition_;
/*! whether the queue is still work */
bool exit_;
// No copying allowed
MtQueueMove(const MtQueueMove&);
void operator=(const MtQueueMove&);
};
template<typename T>
void MtQueueMove<T>::Push(T& item)
{
std::unique_lock<std::mutex> lock(mutex_);
buffer_.push(std::move(item));
empty_condition_.notify_one();
}
template<typename T>
bool MtQueueMove<T>::Pop(T& result)
{
std::unique_lock<std::mutex> lock(mutex_);
empty_condition_.wait(lock,
[this]{ return !buffer_.empty() || exit_; });
if (buffer_.empty())
{
return false;
}
result = std::move(buffer_.front());
buffer_.pop();
return true;
}
template<typename T>
bool MtQueueMove<T>::Front(T& result)
{
std::unique_lock<std::mutex> lock(mutex_);
empty_condition_.wait(lock,
[this]{ return !buffer_.empty() || exit_; });
if (buffer_.empty())
{
return false;
}
result = buffer_.front();
return true;
}
template<typename T>
int MtQueueMove<T>::Size() const
{
std::unique_lock<std::mutex> lock(mutex_);
return static_cast<int>(buffer_.size());
}
template<typename T>
bool MtQueueMove<T>::Empty() const
{
std::unique_lock<std::mutex> lock(mutex_);
return buffer_.empty();
}
template<typename T>
void MtQueueMove<T>::Exit()
{
std::unique_lock<std::mutex> lock(mutex_);
exit_ = true;
empty_condition_.notify_all();
}
}
#endif // MULTIVERSO_MT_QUEUE_H_

Просмотреть файл

@ -1,265 +0,0 @@
#ifndef MULTIVERSO_MULTIVRSO_H_
#define MULTIVERSO_MULTIVRSO_H_
/*!
* \file multiverso.h
* \brief Multiverso API declaration. The applications utilizing Multiverso
* should include this header file.
* \author
* - Feidiao Yang (feiyan@microsoft.com)
* - Fei Gao (feiga@microsoft.com)
*/
#include <string>
#include <vector>
#include "meta.h"
#include "log.h"
#include "row.h"
#include "row_iter.h"
#include "table.h"
#include "table_iter.h"
#include "data_block.h"
#include "parameter_loader.h"
#include "trainer.h"
#include "stop_watch.h"
namespace zmq
{
class socket_t;
}
namespace multiverso
{
class MsgPack;
class LockManager;
class Communicator;
class IAggregator;
//class Server;
template <class Container>
class DoubleBuffer;
template <typename T>
class Row;
class Multiverso
{
friend class TrainerBase;
friend class ParameterLoaderBase;
public:
// 1. -- BEGIN: Multiverso global environment API code area --------- //
/*!
* \brief Initializes the Multiverso environment.
* \param trainers Local trainers
* \param param_loader Parameter loader
* \param config Multiverso configuration
* \param argc Number of commandline arguments, for initializing MPI
* \param argv Commandline arguments, for initializing MPI
* \return 0 on success, or -1 if there is error
*/
static int Init(std::vector<TrainerBase*> &trainers,
ParameterLoaderBase *param_loader, const Config &config,
int *argc, char **argv[]);
/*!
* \brief Initializes the Multiverso environment, this version won't
* handle multi-thread logic
* \param see \ref Init above
*/
static int Init(const Config &config, int *argc, char **argv[]);
/*!
* \brief Closes Multiverso environment.
* \param finalize Only applied in MPI version. If finalize == true,
* MPI will be closed and users do not able to reuse Multiverso
* in another round; or MPI will be kept and uers are allowed to
* re-init Multiverso.
*/
static void Close(bool finalize = true);
/*! \brief Returns the id (rank) of the worker process. */
static int ProcessRank() { return reg_info_.proc_rank; }
/*! \brief Returns the total number of worker processes. */
static int TotalProcessCount() { return reg_info_.proc_count; }
/*! \brief Returns the total number of trainers. */
static int TotalTrainerCount() { return reg_info_.total_trainer_count; }
/*! \brief Returns the total number of servers. */
static int TotalServerCount() { return reg_info_.server_count; }
// -- END: Multiverso global environment API code area -------------- //
// 2. -- BEGIN: Parameter Server Initialization API code area ------- //
/*! \brief Beginning of initialization code area. */
static void BeginConfig();
/*! \brief End of initialization code area. Barrier all worker processes. */
static void EndConfig();
/*!
* \brief Add a logic table to Multiverso environment. This table will
* have 3 copies actually: in server, in local cache and in
* aggregator. And the copies in local cache and aggregator have
* memory pools with the same size. If you would like them to
* have different memory pool size or other options, you will
* you will call the specific AddXXXTable(...) method seperately.
* \param table Identity of the table, indexed from 0
* \param rows Number of rows
* \param cols Number of columns
* \param type Element type
* \param default_format Default format
* \param memory_pool_size If greater than 0, a memory pool will be
* created and the table will resue the memory as possible as
* it can
*/
static void AddTable(integer_t table, integer_t rows, integer_t cols,
Type type, Format default_format, int64_t memory_pool_size = 0);
/*!
* \brief Sends messages to each server of creating a server table.
* This method should be called in order with respect to
* table id. If multiple workers send messages for the same
* table, the first received message will be applied and the
* followings will be ignored.
* \param table Identity of table, indexed from 0
* \param rows Number of rows
* \param cols Number of columns
* \param type Element type
* \param default_format Default format
*/
static void AddServerTable(integer_t table, integer_t rows,
integer_t cols, Type type, Format default_format);
/*!
* \brief Creates a cache table. This method should be called in order
* with respect to table id.
* \param table Identity of table, indexed from 0
* \param rows Number of rows
* \param cols Number of columns
* \param type Element type
* \param default_format Default format
* \param memory_pool_size If greater than 0, a memory pool will be
* created and the rows will reuse the memory as possible as it
* can.
* \return Return 0 on success or -1 if error.
*/
static int AddCacheTable(integer_t table, integer_t rows, integer_t cols,
Type type, Format default_format, int64_t memory_pool_size = 0);
/*!
* \brief Creates a aggregator table.
* \param table Identity of table, indexed from 0
* \param rows Number of rows
* \param cols Number of columns
* \param type Element type
* \param default_format Default format
* \param memory_pool_size If greater than 0, a memory pool will be
* created and the rows will reuse the memory as possible as it
* can.
*/
static void AddAggregatorTable(integer_t table, integer_t rows,
integer_t cols, Type type, Format default_format,
int64_t memory_pool_size = 0);
/*!
* \brief A unified method of setting a row in server, cache and
* aggregator with identical options. If you would like to set
* the row with different settings in these three tables, you
* will call the corresponding SetXXXRow(...) methods seperately.
* \param table Identity of the table
* \param row Identity of the row
* \param format Row format
* \param capacity The maximal number of elements in the row. It is
* fixed for DENSE row and could be automatically growed for
* SPARSE row
*/
static void SetRow(integer_t table, integer_t row, Format format,
integer_t capacity);
/*!
* \brief Sends a message to the server for configuring a row.
* \param table Identity of the table
* \param row Identity of the row
* \param format Row format
* \param capacity The maximal number of elements in the row, it could
* be automatically growed for SPARSE row
*/
static void SetServerRow(integer_t table, integer_t row, Format format,
integer_t capacity);
/*!
* \brief Configures a row in cache.
* \param table Identity of the table
* \param row Identity of the row
* \param format Row format
* \param capacity The maximal number of elements in the row, it could
* be automatically growed for SPARSE row.
*/
static int SetCacheRow(integer_t table, integer_t row, Format format,
integer_t capacity);
/*!
* \brief Configures a row in aggregator.
* \param table Identity of the table
* \param row Identity of the row
* \param format Row format
* \param capacity The maximal number of elements in the row, it could
* be automatically growed for SPARSE row.
*/
static int SetAggregatorRow(integer_t table, integer_t row, Format format,
integer_t capacity);
template <typename T>
static void AddToServer(integer_t table, integer_t row, integer_t col,
T delta)
{
AddToServerPtr(table, row, col, &delta);
}
/*! \brief Flush the aggregation to sever */
static void Flush();
// -- END: Parameter Server Initialization API code area ------------ //
// 3. -- BEGIN: Data API code area ---------------------------------- //
/*! \brief Beginning of training code area.*/
static void BeginTrain();
/*! \brief End of training code area.*/
static void EndTrain();
/*! \brief Begin of each clock period (epoch).*/
static void BeginClock();
/*! \brief End of each clock period (epoch).*/
static void EndClock();
/*! \brief Pushs a data block into Multiverso and triggers an iteration.*/
static void PushDataBlock(DataBlockBase *data_block);
/*! \brief Wait all data block */
static void Wait();
// -- END: Data API code area --------------------------------------- //
private:
static void FlushSetServerRow();
static void AddToServerPtr(
integer_t table, integer_t row, integer_t col, void *delta);
// area of member variables ------------------------------------------/
static RegisterInfo reg_info_;
static int num_trainers_;
static zmq::socket_t *socket_;
static LockManager *lock_manager_;
static LockOption lock_option_;
static Communicator *communicator_;
static IAggregator *aggregator_;
static bool is_pipeline_;
static Barrier* pipeline_barrier_;
static std::vector<TrainerBase*> trainers_;
static ParameterLoaderBase *param_loader_;
static std::vector<Table*> tables0_;
static std::vector<Table*> tables1_;
static DoubleBuffer<std::vector<Table*>> *double_buffer_;
static std::mutex mutex_;
static std::condition_variable wait_cv_;
static std::vector<bool> data_tag_;
static std::vector<MsgPack*> row_config_;
static std::vector<int> row_config_size_;
static int row_config_count_;
};
}
#endif // MULTIVERSO_MULTIVRSO_H_

Просмотреть файл

@ -1,127 +0,0 @@
#ifndef MULTIVERSO_PARAMETER_LOADER_H_
#define MULTIVERSO_PARAMETER_LOADER_H_
/*!
* \file parameter_loader.h
* \brief Defines parameter loader.
*/
#include "meta.h"
#include "mt_queue.h"
#include <thread>
#include <unordered_set>
namespace zmq
{
class socket_t;
}
namespace multiverso
{
/*! \brief Tuple represets the parameters users request */
struct Tuple
{
integer_t table;
integer_t row;
integer_t col;
bool operator==(const Tuple& other) const
{
return (table == other.table
&& row == other.row
&& col == other.col);
}
};
}
namespace std
{
/*!
* \brief Explicity template specializations for std::hash<> in order to
* use Tuple as key of unordered- container
*/
template<> struct hash<multiverso::Tuple>
{
size_t operator()(const multiverso::Tuple& t)const
{
return hash<multiverso::integer_t>()(t.table) ^
hash<multiverso::integer_t>()(t.row) ^
hash<multiverso::integer_t>()(t.col);
}
};
}
namespace multiverso
{
class DataBlockBase;
/*!
* \brief ParameterLoaderBase handles the prameter request through a
* background thread.
*/
class ParameterLoaderBase
{
public:
ParameterLoaderBase();
virtual ~ParameterLoaderBase();
/*!
* \brief Push a data block to loader, loader would get related
* parameter.
*/
void PushDataBlock(DataBlockBase *data_block);
/*!
* \brief Start a parameter loader thread
*/
void Start();
/*!
* \brief Stop the background parameter loader thread
*/
void Stop();
/*!
* \brief Parses a data block to figure out the parameters needed to
* train this data block. Users should implement and override
* this function.
* \prama data_block data block to parse
*/
virtual void ParseAndRequest(DataBlockBase *data_block);
/*!
* \brief Requests a table from server
* \param table table id
*/
void RequestTable(integer_t table);
/*!
* \brief Requests a row from server
* \param table table id
* \param row row id
*/
void RequestRow(integer_t table, integer_t row);
/*!
* \brief Requests a element from server
* \param table table id
* \param row row id
* \param col col id
*/
void RequestElement(integer_t table, integer_t row, integer_t col);
/*! \brief underlying implementation of parameter request */
void ProcessRequest();
void BeginIteration();
void EndIteration();
private:
/*! \brief The entrance function of backgroud thread */
void StartThread();
/*! \brief queue storing data for parse and request */
MtQueueMove<DataBlockBase*> data_queue_;
/*! \brief Set of requested Tuple */
std::unordered_set<Tuple> requests_;
std::thread loader_thread_;
// No copying allowed
ParameterLoaderBase(const ParameterLoaderBase&);
void operator=(const ParameterLoaderBase&);
};
}
#endif // MULTIVERSO_PARAMETER_LOADER_H_

Просмотреть файл

@ -1,207 +0,0 @@
#ifndef MULTIVERSO_ROW_H_
#define MULTIVERSO_ROW_H_
/*!
* \file row.h
* \brief Row container for parameter storage
* \author feiga, feiyan
*/
#include "meta.h"
namespace multiverso
{
class RowBaseIterator;
/*! \brief Interface of row */
class RowBase
{
public:
typedef RowBaseIterator iterator;
virtual ~RowBase() {};
/*!
* \brief Adds delta to the row value of related key
* \param key key of row
* \param delta pointer to delta
* \return sucess or not, 0: success, -1: error
*/
virtual int Add(integer_t key, void *delta) = 0;
/*!
* \brief Add an entire row to the row, only applied for DENSE row.
* \param delta An array pointing to the delta row.
* \return Returns 0 on success or -1 when error occurs.
*/
virtual int Add(void *delta) = 0;
/*!
* \brief Gets row value of related key
* \param key key of row
* \param value pointer to returned value
*/
virtual void At(integer_t key, void *value) = 0;
/**
* \brief Gets capacity of row. Capacity is the maximum number of
* key-value that row can hold
* \return capacity of row
*/
virtual integer_t Capacity() = 0;
/*!
* \brief Gets the number of non-zero key-value pairs
* \return non-zero size of row
*/
virtual integer_t NonzeroSize() = 0;
/*!
* \brief Clears the current row
*/
virtual void Clear() = 0;
/*!
* \brief Gets row id
* \return row id
*/
virtual integer_t RowId() = 0;
/*!
* \brief Gets format of row. Format is either DENSE or SPARSE
* \return format of row
*/
virtual Format RowFormat() = 0;
/*!
* \brief Creates an iterator for the row
* \return pointer to iterator
*/
virtual iterator *BaseIterator() = 0;
/*!
* \brief Serialize a row to a memory
* \param byte memory to store the serialized row
*/
virtual void Serialize(void* byte) = 0;
/*!
* \brief Deserialize the row from byte and then add it into row
* \param byte memory to store the serialized row
*/
virtual void BatchAdd(void* byte) = 0;
/*!
* \brief Serialize a row to a string with format
* row_id col_id:col_val col_id:col_val ...
* \return serialized string
*/
virtual std::string ToString() = 0;
};
template <typename T>
class RowIterator;
/*!
* \brief A hybrid row, can be either DENSE row or SPARSE row
*/
template <typename T>
class Row : public RowBase
{
public:
typedef RowIterator<T> iterator;
friend class RowIterator<T>;
/*!
* \brief Constructs a row based on row_id, format, capacity, memory
* \param row_id id of current row
* \param format format of current row, either DENSE or SPARSE
* \param capacity capacity of current row
* \param memory pointer to the memory block
*/
Row(integer_t row_id, Format format, integer_t capacity,
void *memory = nullptr);
~Row();
int Add(integer_t key, void *delta) override;
int Add(integer_t key, T delta);
int Add(void *delta) override;
void At(integer_t key, void *value) override;
T At(integer_t key);
integer_t Capacity() override;
integer_t NonzeroSize() override;
void Clear() override;
integer_t RowId() override;
Format RowFormat() override;
RowBase::iterator *BaseIterator() override;
iterator Iterator();
void Serialize(void* byte) override;
void BatchAdd(void* byte) override;
std::string ToString() override;
private:
/*!
* \brief Marks key bucket for empty key and deleted key.
* This is only for sparse row. the actual valid key(col id)
* is not less than 0, we set empty key as 0 for efficience
* consideration. Thus in implementation, we would use
* internal key, which equals the actual key plus one
*/
enum KeyType
{
kEmptyKey = 0,
kDeletedKey = -1
};
static const integer_t kDefaultCapacity = 128;
/*!
* \brief Finds position to insert/query, only for sparse row
* \param key key to be found
* \param bucket store the result into bucket
* \return whether found or not
*/
bool FindPosition(const integer_t key, integer_t& bucket);
/*!
* \brief Rehash for sparse row.
*/
void Rehash(bool resize = false);
private:
/*! \brief row id of current row */
integer_t row_id_;
/*! \brief format of current row, should be sparse or dense */
Format format_;
/*! \brief capacity is the maximum number of key-values current
memory block can hold */
integer_t capacity_;
/*! \brief number of element */
integer_t nonzero_size_;
/*! \brief number of deleted key, if deleted key is too much,
we need to re-hash */
integer_t num_deleted_key_;
/*! \brief whether current row has its own memory */
bool has_memory_;
/*! \brief pointer to memory */
void* memory_;
/*! \brief used only by sparse row, store hash keys */
integer_t* key_;
/*! \brief value of related key(sparse) or related index(dense) */
T* value_;
// No copying allowed
Row(const Row<T>&);
void operator=(const Row<T>&);
};
class RowFactoryBase
{
public:
virtual ~RowFactoryBase() {}
virtual RowBase *CreateRow(integer_t row_id, Format format,
integer_t capacity, void *memory) = 0;
virtual int ElementSize() = 0;
static RowFactoryBase *CreateRowFactory(Type type);
};
template <typename T>
class RowFactory : public RowFactoryBase
{
public:
RowFactory() {}
~RowFactory() {}
RowBase *CreateRow(integer_t row_id, Format format, integer_t capacity,
void *memory) override;
int ElementSize() override { return static_cast<int>(sizeof(T)); }
};
}
#endif // MULTIVERSO_ROW_H_

Просмотреть файл

@ -1,73 +0,0 @@
#ifndef MULTIVERSO_ROW_ITER_H_
#define MULTIVERSO_ROW_ITER_H_
/*!
* \file row.h
* \brief Row iterator provides method to traverse a row
*/
#include "meta.h"
namespace multiverso
{
/*!
* \brief Interface of row iterator
*/
class RowBaseIterator
{
public:
virtual ~RowBaseIterator() {};
/*!
* \brief Judges if iterates over the last element
* \return Retruns true if the current iterator pointing
* to a valid element, or false if it points to the end.
*/
virtual bool HasNext() = 0;
/*!
* \brief Iterates to the next element
*/
virtual void Next() = 0;
/*!
* \brief Gets key of current element
* \return key of current element
*/
virtual integer_t Key() = 0;
/*!
* \brief Gets value of current element
* \param pointer to returned value
*/
virtual void Value(void *value) = 0;
};
template <typename T>
class Row;
template <typename T>
class RowIterator : public RowBaseIterator
{
public:
/*!
* \brief Constructs a row iterator
* \param row to create iterator
*/
explicit RowIterator(Row<T> &row);
~RowIterator();
bool HasNext() override;
void Next() override;
integer_t Key() override;
void Value(void *value) override;
T Value();
private:
void SkipInvalidValue();
private:
/*! \brief row reference of parent row */
Row<T>& row_;
/*! \brief current index */
integer_t index_;
};
}
#endif // MULTIVERSO_ROW_ITER_H_

Просмотреть файл

@ -1,98 +0,0 @@
#ifndef MULTIVERSO_SERVER_H_
#define MULTIVERSO_SERVER_H_
/*!
* \file server.h
* \brief Defines the Server class
* \author feiyan, feiga
*/
#include <memory>
#include <vector>
#include <string>
#include <thread>
#include "zmq.hpp"
#include "meta.h"
#include "mt_queue.h"
#include "lock.h"
namespace multiverso
{
class Table;
class MsgPack;
/*!
* \brief The server class is responsible for storing the global model
* parameters in a distributed manner. One application could have
* one or more Server instances with different IDs. And the
* parameters will be distributed among such servers.
*/
class Server
{
public:
/*!
* \brief Creates a server instance and starts a server thread.
* \param server_id Identity of server
* \param num_worker_process Total number of worker processes
* \param endpoint The communication ZQM socket endpoint
*/
Server(int server_id, int num_worker_process, std::string endpoint);
/*! \brief Destroies the server instance and terminates the server thread.*/
~Server();
/*! brief Blocks current threads and waits for the server thread completed.*/
void WaitToComplete();
private:
void StartThread(); // server thread method
void StartUpdateThread(); // server update thread method
void Init(); // initialization at the beginning of server thread
void Clear(); // clean up at the end of server thread
// message processing rountine
void Process_Register(std::shared_ptr<MsgPack> msg_pack);
void Process_Close(std::shared_ptr<MsgPack> msg_pack);
// Returns true if it is the last one comes, or false otherwise
bool Process_Barrier(std::shared_ptr<MsgPack> msg_pack);
void Process_CreateTable(std::shared_ptr<MsgPack> msg_pack);
void Process_SetRow(std::shared_ptr<MsgPack> msg_pack);
void Process_Clock(std::shared_ptr<MsgPack> msg_pack);
void Process_EndTrain(std::shared_ptr<MsgPack> msg_pack);
void Process_Get(std::shared_ptr<MsgPack> msg_pack);
void Process_Add(std::shared_ptr<MsgPack> msg_pack);
// helper function for processing get row request
void Process_GetRow(integer_t table, integer_t row, integer_t col,
std::shared_ptr<MsgPack> msg_pack,
int& send_ret_size, MsgPack*& reply);
void DumpModel();
// area of member variables ------------------------------------------/
int server_id_; // server identity
int worker_proc_count_; // total number of worker processes
std::string endpoint_;
zmq::socket_t *router_;
zmq::pollitem_t *poll_items_;
int poll_count_;
std::vector<std::shared_ptr<MsgPack>> waiting_msg_;
bool is_working_;
bool inited_;
std::thread server_thread_;
std::thread update_thread_;
int max_delay_;
std::vector<int> clocks_;
std::vector<std::shared_ptr<MsgPack>> clock_msg_;
std::vector<Table*> tables_;
MtQueueMove<std::shared_ptr<MsgPack>> update_queue_;
LockManager lock_pool_;
// No copying allowed
Server(const Server&);
void operator=(const Server&);
};
}
#endif // MULTIVERSO_SERVER_H_

Просмотреть файл

@ -1,54 +0,0 @@
#ifndef MULTIVERSO_STOP_WATCH_
#define MULTIVERSO_STOP_WATCH_
#include <cstdint>
/*!
* \file stop_watch.h
* \brief Defines a StopWatch class
* \author feiyan
*/
namespace multiverso
{
/*!
* \brief The StopWatch class is a timer like StopWatch class in C#. In
* Windows' version, it utilizes some high resolution facilities,
* or standard C clock() function instead.
*/
class StopWatch
{
public:
/*! \brief Creates a StopWatch and starts timing. */
StopWatch();
~StopWatch();
/*! \brief Clears the status and restart timing. */
void Restart();
/*! \brief Starts timing. Does nothing if it is already running. */
void Start();
/*!
* \brief Stops timing and accumulates the elapsed time since last
* valid starting. Does nothing if it is already stopped.
*/
void Stop();
/*! \brief Returns if the StopWatch instance is running (timing). */
bool IsRunning();
/*!
* \brief Returns the elapsed time accumulated between the valid starts
* and stops, it includes the time from the last valid starting
* to now if it is in running status.
*/
double ElapsedSeconds();
private:
int64_t GetTickPerSec();
int64_t GetCurrentTick();
int64_t tick_per_sec_;
int64_t elapsed_tick_;
int64_t start_tick_;
};
}
#endif // MULTIVERSO_STOP_WATCH_

Просмотреть файл

@ -1,92 +0,0 @@
#ifndef MULTIVERSO_TABLE_H_
#define MULTIVERSO_TABLE_H_
/*!
* \file table.h
* \brief Table declaration.
*/
#include "meta.h"
#include <mutex>
#include <vector>
namespace multiverso
{
struct RowInfo
{
public:
RowInfo(Format _format, integer_t _capacity, integer_t _index = -1);
Format format;
integer_t capacity;
integer_t index;
RowBase* row;
};
class RowBase;
class TableIterator;
class RowFactoryBase;
/*! \brief The class Table is a container of rows. */
class Table
{
public:
typedef TableIterator iterator;
friend class TableIterator;
/*!
* \beirf Creates a table.
* \param table_id Table identity
* \param rows Number of rows
* \param cols Number of columns
* \param Element type
* \param default_format Default row format
* \param memory_pool_size Memory pool size. When creating rows,
* the table will reuse the memory pool if available.
*/
Table(integer_t table_id, integer_t rows, integer_t cols, Type type,
Format default_format, int64_t memory_pool_size = 0);
~Table();
/*!
* \brief Configures a row.
* \param row_id Row id
* \param format Row format.
* \param capacity The initial maximal number of elements the row
* stores, it is fixed for DENSE row (array), and can be
* auto-growed for SPARSE row (hash table).
* \return Returns 0 on success, or -1 with error.
*/
int SetRow(integer_t row_id, Format format, integer_t capacity);
/*! \brief Returns a pointer to the specific row, or NULL if not avaiable. */
RowBase *GetRow(integer_t row_id);
/*! \brief Returns a reference to a specified RowInfo. */
RowInfo *GetRowInfo(integer_t row_id);
/*! \brief Removes all rows in the table. */
void Clear();
/*! \brief Get element size of current table */
int ElementSize();
/*! \brief Returns an iterator for accessing all rows. */
TableIterator Iterator();
private:
integer_t table_id_;
char *memory_pool_;
int64_t memory_size_;
int64_t used_memory_size_;
RowFactoryBase* row_factory_;
int element_size_;
std::vector<RowInfo> row_info_;
std::vector<RowBase*> rows_;
std::mutex mutex_;
// No copying allowed
Table(const Table&);
void operator=(const Table&);
};
}
#endif // MULTIVERSO_TABLE_H_

Просмотреть файл

@ -1,45 +0,0 @@
#ifndef MULTIVERSO_TABLE_ITER_H_
#define MULTIVERSO_TABLE_ITER_H_
/*!
* \file table_iter.h
* \brief Table iterator declaration.
*/
#include "meta.h"
namespace multiverso
{
class RowBase;
class Table;
/*! \brief The class TableIterator is for accessing the rows in Table. */
class TableIterator
{
public:
/*! \brief Creates an iterator for accessing the table. */
explicit TableIterator(Table &table);
~TableIterator();
/*! \brief Returns true if current element is valid,
or false if it points to the end.*/
bool HasNext();
/*!
* \brief Move the iterator to the next position.
* \return Returns 0 if moving successfully, or -1 if pointing to the end.
*/
void Next();
/*! \brief Returns current row id, or -1 if pointing to the end. */
integer_t RowId();
/// Returns a pointer to current row, or NULL if pointing to the end.
RowBase *Row();
private:
/*! \brief Table to iterator */
Table& table_;
/*! \brief Current row index */
integer_t idx_;
};
}
#endif // MULTIVERSO_TABLE_ITER_H_

Просмотреть файл

@ -1,129 +0,0 @@
#ifndef MULTIVERSO_TRAINER_H_
#define MULTIVERSO_TRAINER_H_
/*!
* \file trainer.h
* \brief Defines the TrainerBase interface.
* \author feiyan
*/
#include <atomic>
#include <thread>
#include <mutex>
#include <vector>
#include "meta.h"
#include "mt_queue.h"
namespace multiverso
{
class DataBlockBase;
class RowBase;
template <typename T>
class Row;
class Barrier;
class Table;
/*!
* \brief The TrainerBase class defines an interface for user-customized
* Trainer classes.
*/
class TrainerBase
{
public:
/*! \brief Assigns a trainer id to the instance. */
TrainerBase();
virtual ~TrainerBase();
/*!
* \brief Users override this method to train/update the model given a
* block of data, or other customized logic routine. This method is
* called by Multiverso working threads at each iteration (for each
* train/test data block).
*/
virtual void TrainIteration(DataBlockBase* data_block) {}
/*!
* \brief This method will be called at the beginning of each clock
* period (signaled by a trivial data block of type "BEGINCLOCK").
*/
virtual void BeginClock() {}
/*!
* \brief This method will be called at the end of each clock period
* (signaled by a trivial data block of type "ENDCLOCK").
*/
virtual void EndClock() {}
/*! \brief Returns the id of the trainer instance (indexed from 0).*/
int TrainerId() const { return trainer_id_; }
/*! \brief Returns the number of local trainers.*/
int TrainerCount() const { return trainer_count_; }
/*! \brief Returns a pointer to the specified table */
Table *GetTable(integer_t table_id);
/*! \brief Returns a reference to a specific row.*/
template <typename T>
Row<T> &GetRow(integer_t table_id, integer_t row_id)
{
Row<T> *row = static_cast<Row<T>*>(GetRowPtr(table_id, row_id));
return *row;
}
/*! \brief Adds an element delta to a specific element.*/
template <typename T>
void Add(integer_t table_id, integer_t row_id, integer_t col_id, T delta)
{
AddPtr(table_id, row_id, col_id, &delta);
}
/*! \brief Adds a row delta to a specified row. */
template <typename T>
void Add(integer_t table_id, integer_t row_id, std::vector<T> &delta)
{
Add(table_id, row_id, delta.data());
}
/*! \brief Adds a row delta to a specified row. */
void Add(integer_t table_id, integer_t row_id, void *delta);
/*! \brief Finished a clock period of training and sync.*/
void Clock();
void BeginIteration();
void EndIteration();
/*!
* \brief Push a data block into the data queue of the trainer.
* \param data_block A data block for training in an iteration (or
* other logic such as test or clock signals).
*/
void PushDataBlock(DataBlockBase *data_block);
/*! \brief Starts a training thread.*/
void Start();
/*! \brief Stops the training thread.*/
void Stop();
private:
void StartThread();
/*! \brief Returns a pointer to the specified row. */
RowBase *GetRowPtr(integer_t table_id, integer_t row_id);
/*! \brief Adds a delta to the specific element with pointer manner. */
void AddPtr(integer_t table_id, integer_t row_id, integer_t col_id,
void *delta);
// -- area of member variables ---------------------------------------/
std::thread trainer_thread_;
MtQueueMove<DataBlockBase*> data_queue_;
int trainer_id_;
static std::atomic<int> trainer_count_; // the total trainer count in local
static std::mutex mtx_;
static Barrier barrier_;
// No copying allowed
TrainerBase(const TrainerBase&);
void operator=(const TrainerBase&);
};
}
#endif // MULTIVERSO_TRAINER_H_

Просмотреть файл

@ -1,31 +0,0 @@
#ifndef MULTIVERSO_VECTOR_CLOCK_
#define MULTIVERSO_VECTOR_CLOCK_
/*!
* \file vector_clock.h
* \brief Defines VectorClock for multi thread/process
*/
#include <vector>
namespace multiverso
{
/*!
* \brief VectorClock manages states of multi threads/processes clock
*/
class VectorClock
{
public:
explicit VectorClock(int n);
/*!
* \brief Updates i-th clock
* \return Return true if i-th clock is slowest, false otherwise
*/
bool Update(int i);
private:
std::vector<int> vectors_;
int clock_; // min clock of all clocks in vector
};
}
#endif // MULTIVERSO_VECTOR_CLOCK_

Просмотреть файл

@ -1,57 +0,0 @@
#ifndef MULTIVERSO_ZMQ_UTIL_H_
#define MULTIVERSO_ZMQ_UTIL_H_
/*!
* \file zmq_util.h
* \brief Wraps the ZMQ facilities
* \author feiyan
*/
#include <string>
#include <vector>
#include <queue>
#include <memory>
#include "zmq.hpp"
namespace multiverso
{
const std::string kCOMM_ENDPOINT = "inproc://comm"; // communicator endpoint
const std::string kSERVER_ENDPOINT = "inproc://server"; // server endpoint
const int kZMQ_IO_THREAD_NUM = 1;
const int kZMQ_POLL_TIMEOUT = 0;
class MsgPack;
class ZMQUtil
{
public:
/*!
* \brief Creates and returns a ZMQ DEALER socket connecting to
* communication end point.
*/
static zmq::socket_t *CreateSocket();
/*!
* \brief Returns a reference to the ZMQ contest, mainly for creating
* sockets.
*/
static zmq::context_t &GetZMQContext() { return zmq_context_; }
/*!
* \brief Polls a group of ZMQ sockets to probe if there are received
* messages. If so, pushes them into the output queue.
* \param items ZMQ poll item array
* \param count Size of the item array
* \param sockets The corresponding sockets (with same order in items)
* \param msg_queue Queue for receiving the messages
*/
static void ZMQPoll(zmq::pollitem_t *items, int count,
std::vector<zmq::socket_t*> &sockets,
std::queue<std::shared_ptr<MsgPack>> &msg_queue);
private:
static zmq::context_t zmq_context_;
};
}
#endif // MULTIVERSO_ZMQ_UTIL_H_

Просмотреть файл

@ -1,6 +0,0 @@
Root folder keeps the origin structure of current multiverso.
This is the place for new version multiverso code.

Просмотреть файл

@ -1,83 +0,0 @@
#include "arena.h"
#include "log.h"
#include <stdlib.h>
namespace multiverso {
static const size_t kDefaultInitialBlockSize = 1 << 20; // 1MB
static const size_t kDefaultBlockUnitSize = 1 << 12; // 4KB
Arena::Arena() {
initial_block_size_ = kDefaultInitialBlockSize;
block_unit_size_ = kDefaultBlockUnitSize;
initial_mem_ = AllocateNew(initial_block_size_);
next_ptr_ = initial_mem_.memory;
available_size_ = initial_mem_.size;
total_size_ = initial_mem_.size;
request_size_ = 0;
request_time_ = 0;
}
Arena::~Arena() {
free(initial_mem_.memory);
FreeBlocks();
}
void Arena::Reset() {
Log::Info("in reset\n");
FreeBlocks();
Resize();
next_ptr_ = initial_mem_.memory;
available_size_ = initial_mem_.size;
total_size_ = initial_mem_.size;
request_size_ = 0;
request_time_ = 0;
waiter_.Notify();
}
char* Arena::AllocateFallback(size_t bytes) {
if (bytes > block_unit_size_ / 4) {
MemBlock block = AllocateNew(bytes);
mem_blocks_.push_back(block);
return block.memory;
} else {
MemBlock block = AllocateNew(block_unit_size_);
mem_blocks_.push_back(block);
next_ptr_ = block.memory + bytes;
available_size_ = block_unit_size_ - bytes;
return block.memory;
}
}
void Arena::Resize() {
block_unit_size_ = 10 * (request_size_ / request_time_);
if (true) { // TODO(feiga): judge if it's necessary to re-alloc
initial_block_size_ = request_size_ / 2;
free(initial_mem_.memory);
initial_mem_ = AllocateNew(initial_block_size_);
}
}
// TODO(feiga): alignment
Arena::MemBlock Arena::AllocateNew(size_t bytes) {
// Add log, since this is not efficient, and should be called as less as possible
// Log(INFO) << "Allocate new ";
MemBlock result;
result.memory = reinterpret_cast<char*>(malloc(bytes));
result.size = bytes;
total_size_ += bytes;
return result;
}
void Arena::FreeBlocks() {
for (auto m : mem_blocks_) delete m.memory;
mem_blocks_.clear();
}
}

Просмотреть файл

@ -1,89 +0,0 @@
#ifndef MULTIVERSO_ARENA_H_
#define MULTIVERSO_ARENA_H_
#include <sstream>
#include "base.h"
#include "waiter.h"
namespace multiverso {
// Arena is a continuous chunk of memory. It is designed for the frequent
// message allocation in multiverso. Arena records the average memory size
// and total size requested by custmor between two Arena::Reset() calls. And
// arena adjust the initial block size as half of total memory and
// block unit size as 2 * ave(size) when Reset() for next time's uses.
//
// Arena is not thread-safe and is designed to use within one thread.
class Arena {
public:
Arena();
~Arena();
// Allocate a block memory
// TODO(feiga): consider memory alignment
char* Allocate(size_t bytes);
void Before() { waiter_.Wait(); }
void After() { waiter_.Reset(); }
void Reset();
std::string DebugString() const {
std::ostringstream ss;
ss << "[Arena]: Total size = " << total_size_
<< " Request size = " << request_size_
<< " Request time = " << request_time_
<< std::endl;
return ss.str();
}
private:
struct MemBlock {
char* memory;
size_t size;
};
// The initial memory is relatively big. The best case is this memory
// is enough for use, as well not too big to waste.
MemBlock initial_mem_;
// After initial_mem_ is exhausted, we allocate a series of default-size
// block for further use.
std::vector<MemBlock> mem_blocks_;
Waiter waiter_;
char* next_ptr_;
size_t available_size_;
size_t total_size_; // total size arena holds
size_t request_size_; // sum of requested size
size_t request_time_; // time of request
size_t initial_block_size_;
size_t block_unit_size_;
MemBlock AllocateNew(size_t bytes);
char* AllocateFallback(size_t bytes);
void FreeBlocks();
void Resize();
DISALLOW_COPY_AND_ASSIGN(Arena);
};
inline char* Arena::Allocate(size_t bytes) {
// TODO
request_size_ += bytes;
++request_time_;
if (available_size_ >= bytes) {
available_size_ -= bytes;
char* result = next_ptr_;
next_ptr_ += bytes;
return result;
} else {
return AllocateFallback(bytes);
}
}
} // namespace multiverso
#endif // MULTIVERSO_ARENA_H_

Просмотреть файл

@ -1,45 +0,0 @@
#include "arena.h"
#include <iostream>
#include <zmq.hpp>
#include <stop_watch.h>
#include <zmq_util.h>
int main()
{
multiverso::Arena arena;
std::cout << arena.DebugString();
//zmq::message_t* msg = new (arena.Allocate(sizeof(zmq::message_t)))
// zmq::message_t(3 * sizeof(int));
multiverso::StopWatch watch;
for (int i = 0; i < 10000; ++i){
zmq::message_t* msg = multiverso::ZMQUtil::NewZMQMessage(&arena, 256, i == 9);
//std::cout << "msg size = " << msg->size() << std::endl;
//std::cout << arena.DebugString();
}
std::cout << "arena time : " << watch.ElapsedSeconds() << std::endl;
std::cout << arena.DebugString();
arena.Reset();
watch.Restart();
for (int i = 0; i < 10000; ++i){
zmq::message_t* msg = multiverso::ZMQUtil::NewZMQMessage(&arena, 256, i == 9);
//std::cout << "msg size = " << msg->size() << std::endl;
//std::cout << arena.DebugString();
}
std::cout << "arena time : " << watch.ElapsedSeconds() << std::endl;
std::cout << arena.DebugString();
watch.Restart();
for (int i = 0; i < 10000; ++i)
{
zmq::message_t* msg = new zmq::message_t(256);
}
std::cout << "naive time : " << watch.ElapsedSeconds() << std::endl;
return 0;
}

Просмотреть файл

@ -1,15 +0,0 @@
#ifndef MULTIVERSO_BASE_H_
#define MULTIVERSO_BASE_H_
#include <string>
#include <vector>
namespace multiverso {
#define DISALLOW_COPY_AND_ASSIGN(Type) \
Type(const Type&) = delete; \
void operator=(const Type&) = delete
} // namespace multiverso
#endif // MULTIVERSO_BASE_H_

Просмотреть файл

@ -1,24 +0,0 @@
#ifndef MULTIVERSO_BOUND_QUEUE_H_
#define MULTIVERSO_BOUND_QUEUE_H_
#include "base.h"
namespace multiverso {
template <typename T, int N>
class BoundQueue {
public:
void Push(T* item);
void Pop(T* item);
T& Front();
private:
T queue_[N];
index_t index_;
};
template <typename T>
typedef BoundQueue<T, 2> DoubleBuffer<T>;
}
#endif // MULTIVERSO_BOUND_QUEUE_H_

Просмотреть файл

@ -1,59 +0,0 @@
#ifndef MULTIVERSO_MESSAGE_H_
#define MULTIVERSO_MESSAGE_H_
#include <functional>
#include "base.h"
// NOTE(feiga): using zmq c api instead of c++
//#include <third_party/zmq/zmq.h>
namespace multiverso {
class Arena;
// Callback function type when message is deleted.
typedef std::function<void(Arena&)> MsgDeleteCallBack;
// Currently Message is a wrapper of ZeroMQ message
// TODO(feiga), considering a more general message interface. Zmq can be
// a kind of implementation.
class Message {
public:
Message();
explicit Message(size_t size);
// Allocate a message from arena
Message(Arena& arena, size_t size);
// Construct a Message from a pre-allocated memory
Message(char* mem, size_t size);
// Delete message
~Message();
void* RawPtr();
template<typename T>
T* RawPtr() { return reinterpret_cast<T*>(RawPtr()); }
private:
enum MemOwner {
kArena,
kInternal,
kOutside
};
char header_[16];
char* mem_;
size_t size_;
MemOwner owner_;
// TODO: Whether copy allowed?
}
} // namespace multiverso
#endif // MULTIVERSO_MESSAGE_H_

Просмотреть файл

@ -1,39 +0,0 @@
// The interface is following the design of Piccolo paper
// Refer to http://piccolo.news.cs.nyu.edu/piccolo.pdf for details.
#ifndef MULTIVERSO_TABLE_INTERFACE_H_
#define MULTIVERSO_TABLE_INTERFACE_H_
namespace multiverso {
// Interface for Multiverso shared parameters. Key is the type of global shared
// Value is the parameters for machine learning tasks. Can be Matrix, Vector,
// Hash Table, Hybrid Table...etc.
template <typename Key, typename Value>
class TableInterface {
public:
virtual void Init();
void Clear();
void Get(const Key& key, Value* value);
virtual AsyncGet(const Key& key, Value* value) = 0;
void Put(const Key& key, Value* value);
void Update(const Key& key, Value* value) = 0;
void Flush();
virtual void Partition();
protected:
virtual ~TableInterface() {}
};
} // namespace multiverso
#endif // MULTIVERSO_TABLE_INTERFACE_H_

Просмотреть файл

@ -1,32 +0,0 @@
#ifndef MULTIVERSO_WAITER_H_
#define MULTIVERSO_WAITER_H_
#include <mutex>
#include <condition_variable>
namespace multiverso {
class Waiter {
public:
Waiter() : ready_(true) {}
void Wait() {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this](){ return ready_; } );
}
void Notify() {
std::unique_lock<std::mutex> lock(mutex_);
ready_ = true;
cv_.notify_one();
};
void Reset() {
std::unique_lock<std::mutex> lock(mutex_);
ready_ = false;
}
private:
mutable std::mutex mutex_;
std::condition_variable cv_;
bool ready_;
};
}
#endif // MULTIVERSO_WAITER_H_

Просмотреть файл

@ -1,27 +0,0 @@
#ifndef MULTIVERSO_ZMQ_HELPER_H_
#define MULTIVERSO_ZMQ_HELPER_H_
#include "zmq_util.h"
#include "arena.h"
namespace multiverso {
void FreeZMQMessage(void* data, void* hint) {
Arena* arena = static_cast<Arena*>(data);
bool* last = static_cast<bool*>(hint);
if (*last) arena->Reset();
}
static bool kLast = true;
static bool kNotLast = false;
zmq::message_t* NewZMQMessage(Arena* arena, size_t size, bool last) {
char* memory = arena->Allocate(sizeof(zmq::message_t) + size);
zmq::message_t* msg = new (memory)zmq::message_t(
memory + sizeof(zmq::message_t), size, FreeZMQMessage,
last ? &kLast : &kNotLast);
return msg;
}
}
#endif

90
next/IMultiverso/new/actor.cpp → next/new/actor.cpp Executable file → Normal file
Просмотреть файл

@ -1,46 +1,46 @@
#include "actor.h"
#include "message.h"
#include "mt_queue.h"
#include "zoo.h"
#include "log.h"
namespace multiverso {
Actor::Actor(const std::string& name) : name_(name) {
Zoo::Get()->Register(name, this);
}
Actor::~Actor() {}
void Actor::Start() {
mailbox_.reset(new MtQueue<MessagePtr>());
thread_.reset(new std::thread(&Actor::Main, this));
}
void Actor::Stop() {
while (!mailbox_->Empty()) {;}
mailbox_->Exit();
thread_->join();
}
void Actor::Accept(MessagePtr& msg) { mailbox_->Push(msg); }
void Actor::Main() {
// Log::Info("Start to run actor %s\n", name().c_str());
MessagePtr msg;
while (mailbox_->Pop(msg)) {
if (handlers_.find(msg->type()) != handlers_.end()) {
handlers_[msg->type()](msg);
} else if (handlers_.find(MsgType::Default) != handlers_.end()) {
handlers_[MsgType::Default](msg);
} else {
CHECK(false); // Fatal error
}
}
}
void Actor::DeliverTo(const std::string& dst_name, MessagePtr& msg) {
Zoo::Get()->Deliver(dst_name, msg);
}
#include "actor.h"
#include "message.h"
#include "mt_queue.h"
#include "zoo.h"
#include "log.h"
namespace multiverso {
Actor::Actor(const std::string& name) : name_(name) {
Zoo::Get()->Register(name, this);
}
Actor::~Actor() {}
void Actor::Start() {
mailbox_.reset(new MtQueue<MessagePtr>());
thread_.reset(new std::thread(&Actor::Main, this));
}
void Actor::Stop() {
while (!mailbox_->Empty()) {;}
mailbox_->Exit();
thread_->join();
}
void Actor::Accept(MessagePtr& msg) { mailbox_->Push(msg); }
void Actor::Main() {
// Log::Info("Start to run actor %s\n", name().c_str());
MessagePtr msg;
while (mailbox_->Pop(msg)) {
if (handlers_.find(msg->type()) != handlers_.end()) {
handlers_[msg->type()](msg);
} else if (handlers_.find(MsgType::Default) != handlers_.end()) {
handlers_[MsgType::Default](msg);
} else {
CHECK(false); // Fatal error
}
}
}
void Actor::DeliverTo(const std::string& dst_name, MessagePtr& msg) {
Zoo::Get()->Deliver(dst_name, msg);
}
}

128
next/IMultiverso/new/actor.h → next/new/actor.h Executable file → Normal file
Просмотреть файл

@ -1,65 +1,65 @@
#ifndef MULTIVERSO_ACTOR_H_
#define MULTIVERSO_ACTOR_H_
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include "message.h"
namespace multiverso {
template<typename T> class MtQueue;
// The basic computation and communication unit in the system
class Actor {
public:
explicit Actor(const std::string& name);
virtual ~Actor();
// Start to run the Actor
void Start();
// Stop to run the Actor
void Stop();
// Accept a message from other actors
void Accept(MessagePtr&);
void Wait();
const std::string name() const { return name_; }
// Message response function
using Task = std::function<void(MessagePtr&)>;
protected:
void RegisterTask(const MsgType& type, const Task& task) {
handlers_.insert({type, task});
}
void DeliverTo(const std::string& dst_name, MessagePtr& msg);
// Run in a background thread to receive msg from other actors and process
// messages based on registered handlers
virtual void Main();
std::string name_;
std::unique_ptr<std::thread> thread_;
// message queue
std::unique_ptr<MtQueue<std::unique_ptr<Message>> > mailbox_;
std::unordered_map<MsgType, Task> handlers_;
};
namespace actor {
const std::string kCommunicator = "communicator";
const std::string kController = "controller";
const std::string kServer = "server";
const std::string kWorker = "worker";
}
} // namespace multiverso
#ifndef MULTIVERSO_ACTOR_H_
#define MULTIVERSO_ACTOR_H_
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include "message.h"
namespace multiverso {
template<typename T> class MtQueue;
// The basic computation and communication unit in the system
class Actor {
public:
explicit Actor(const std::string& name);
virtual ~Actor();
// Start to run the Actor
void Start();
// Stop to run the Actor
void Stop();
// Accept a message from other actors
void Accept(MessagePtr&);
void Wait();
const std::string name() const { return name_; }
// Message response function
using Task = std::function<void(MessagePtr&)>;
protected:
void RegisterTask(const MsgType& type, const Task& task) {
handlers_.insert({type, task});
}
void DeliverTo(const std::string& dst_name, MessagePtr& msg);
// Run in a background thread to receive msg from other actors and process
// messages based on registered handlers
virtual void Main();
std::string name_;
std::unique_ptr<std::thread> thread_;
// message queue
std::unique_ptr<MtQueue<std::unique_ptr<Message>> > mailbox_;
std::unordered_map<MsgType, Task> handlers_;
};
namespace actor {
const std::string kCommunicator = "communicator";
const std::string kController = "controller";
const std::string kServer = "server";
const std::string kWorker = "worker";
}
} // namespace multiverso
#endif // MULTIVERSO_ANIMAL_H_

Просмотреть файл

@ -1,116 +1,116 @@
#ifndef MULTIVERSO_STATIC_TABLE_H_
#define MULTIVERSO_STATIC_TABLE_H_
#include "table_interface.h"
namespace multiverso {
// A distributed shared std::vector<T> table
template <typename T>
class ArrayWorker : public WorkerTable {
public:
explicit ArrayWorker(size_t size) : WorkerTable(), size_(size) {
table_.resize(size);
num_server_ = Zoo::Get()->num_servers();
server_offsets_.push_back(0);
CHECK(size_ > Zoo::Get()->num_servers()); // not support too small size vector
int length = static_cast<int>(size_) / Zoo::Get()->num_servers();
for (int i = 1; i < Zoo::Get()->num_servers(); ++i) {
server_offsets_.push_back(i * length); // may not balance
}
server_offsets_.push_back(size_);
}
std::vector<T>& raw() { return table_; }
// Get all element
void Get() {
int all_key = -1;
WorkerTable::Get(Blob(&all_key, sizeof(int)));
}
// Add all element
void Add(T* data, size_t size) {
CHECK(size == table_.size());
int all_key = -1;
WorkerTable::Add(Blob(&all_key, sizeof(int)), Blob(data, size * sizeof(T)));
}
int Partition(const std::vector<Blob>& kv,
std::unordered_map<int, std::vector<Blob> >* out) override {
CHECK(kv.size() == 1 || kv.size() == 2);
for (int i = 0; i < num_server_; ++i) (*out)[i].push_back(kv[0]);
if (kv.size() == 2) {
CHECK(kv[1].size() == table_.size() * sizeof(T));
for (int i = 0; i < num_server_; ++i) {
Blob blob(kv[1].data() + server_offsets_[i] * sizeof(T),
(server_offsets_[i + 1] - server_offsets_[i]) * sizeof(T));
(*out)[i].push_back(blob);
}
}
return num_server_;
}
void ProcessReplyGet(std::vector<Blob>& reply_data) override {
CHECK(reply_data.size() == 2);
int id = (reply_data[0]).As<int>();
CHECK(reply_data[1].size<T>() == (server_offsets_[id+1] - server_offsets_[id]));
memcpy(table_.data() + server_offsets_[id], // * sizeof(T),
reply_data[1].data(), reply_data[1].size());
}
private:
std::vector<T> table_;
size_t size_;
int num_server_;
std::vector<size_t> server_offsets_;
};
// TODO(feiga): rename. The name static is inherited from last version
// The storage is a continuous large chunk of memory
template <typename T>
class ArrayServer : public ServerTable {
public:
explicit ArrayServer(size_t size) : ServerTable() {
server_id_ = Zoo::Get()->rank();
size_ = size / Zoo::Get()->size();
if (server_id_ == Zoo::Get()->num_servers()-1) { // last server
size_ += size % Zoo::Get()->num_servers();
}
storage_.resize(size_);
}
void ProcessAdd(const std::vector<Blob>& data) override {
#ifdef MULTIVERSO_USE_BLAS
// MKL update
Log::Fatal("Not implemented yet\n");
#else
Blob keys = data[0], values = data[1];
CHECK(keys.size<int>() == 1 && keys.As<int>() == -1); // Always request whole table
CHECK(values.size() == size_ * sizeof(T));
for (int i = 0; i < size_; ++i) storage_[i] += values.As<T>(i);
#endif
}
void ProcessGet(const std::vector<Blob>& data,
std::vector<Blob>* result) override {
size_t key_size = data[0].size<int>();
CHECK(key_size == 1 && data[0].As<int>() == -1); // Always request the whole table
Blob key(sizeof(int)); key.As<int>() = server_id_;
Blob value(storage_.data(), sizeof(T) * size_);
result->push_back(key);
result->push_back(value);
}
private:
int server_id_;
// T* storage_;
std::vector<T> storage_;
size_t size_; // number of element with type T
};
}
#ifndef MULTIVERSO_STATIC_TABLE_H_
#define MULTIVERSO_STATIC_TABLE_H_
#include "table_interface.h"
namespace multiverso {
// A distributed shared std::vector<T> table
template <typename T>
class ArrayWorker : public WorkerTable {
public:
explicit ArrayWorker(size_t size) : WorkerTable(), size_(size) {
table_.resize(size);
num_server_ = Zoo::Get()->num_servers();
server_offsets_.push_back(0);
CHECK(size_ > Zoo::Get()->num_servers()); // not support too small size vector
int length = static_cast<int>(size_) / Zoo::Get()->num_servers();
for (int i = 1; i < Zoo::Get()->num_servers(); ++i) {
server_offsets_.push_back(i * length); // may not balance
}
server_offsets_.push_back(size_);
}
std::vector<T>& raw() { return table_; }
// Get all element
void Get() {
int all_key = -1;
WorkerTable::Get(Blob(&all_key, sizeof(int)));
}
// Add all element
void Add(T* data, size_t size) {
CHECK(size == table_.size());
int all_key = -1;
WorkerTable::Add(Blob(&all_key, sizeof(int)), Blob(data, size * sizeof(T)));
}
int Partition(const std::vector<Blob>& kv,
std::unordered_map<int, std::vector<Blob> >* out) override {
CHECK(kv.size() == 1 || kv.size() == 2);
for (int i = 0; i < num_server_; ++i) (*out)[i].push_back(kv[0]);
if (kv.size() == 2) {
CHECK(kv[1].size() == table_.size() * sizeof(T));
for (int i = 0; i < num_server_; ++i) {
Blob blob(kv[1].data() + server_offsets_[i] * sizeof(T),
(server_offsets_[i + 1] - server_offsets_[i]) * sizeof(T));
(*out)[i].push_back(blob);
}
}
return num_server_;
}
void ProcessReplyGet(std::vector<Blob>& reply_data) override {
CHECK(reply_data.size() == 2);
int id = (reply_data[0]).As<int>();
CHECK(reply_data[1].size<T>() == (server_offsets_[id+1] - server_offsets_[id]));
memcpy(table_.data() + server_offsets_[id], // * sizeof(T),
reply_data[1].data(), reply_data[1].size());
}
private:
std::vector<T> table_;
size_t size_;
int num_server_;
std::vector<size_t> server_offsets_;
};
// TODO(feiga): rename. The name static is inherited from last version
// The storage is a continuous large chunk of memory
template <typename T>
class ArrayServer : public ServerTable {
public:
explicit ArrayServer(size_t size) : ServerTable() {
server_id_ = Zoo::Get()->rank();
size_ = size / Zoo::Get()->size();
if (server_id_ == Zoo::Get()->num_servers()-1) { // last server
size_ += size % Zoo::Get()->num_servers();
}
storage_.resize(size_);
}
void ProcessAdd(const std::vector<Blob>& data) override {
#ifdef MULTIVERSO_USE_BLAS
// MKL update
Log::Fatal("Not implemented yet\n");
#else
Blob keys = data[0], values = data[1];
CHECK(keys.size<int>() == 1 && keys.As<int>() == -1); // Always request whole table
CHECK(values.size() == size_ * sizeof(T));
for (int i = 0; i < size_; ++i) storage_[i] += values.As<T>(i);
#endif
}
void ProcessGet(const std::vector<Blob>& data,
std::vector<Blob>* result) override {
size_t key_size = data[0].size<int>();
CHECK(key_size == 1 && data[0].As<int>() == -1); // Always request the whole table
Blob key(sizeof(int)); key.As<int>() = server_id_;
Blob value(storage_.data(), sizeof(T) * size_);
result->push_back(key);
result->push_back(value);
}
private:
int server_id_;
// T* storage_;
std::vector<T> storage_;
size_t size_; // number of element with type T
};
}
#endif // MULTIVERSO_STATIC_TABLE_H_

124
next/IMultiverso/new/blob.h → next/new/blob.h Executable file → Normal file
Просмотреть файл

@ -1,63 +1,63 @@
#ifndef MULTIVERSO_BLOB_H_
#define MULTIVERSO_BLOB_H_
#include <memory>
#include <string>
#include "log.h"
namespace multiverso {
// Manage a chunk of memory. Blob can share memory with other Blobs.
// Never use external memory. All external memory should be managed by itself
class Blob {
public:
// an empty blob
Blob() {};
explicit Blob(size_t size) : size_(size) {
CHECK(size > 0);
data_.reset(new char[size]);
}
// Construct from external memory. Will copy a new piece
Blob(void* data, size_t size) : size_(size) {
data_.reset(new char[size]);
memcpy(data_.get(), data, size_);
}
Blob(const Blob&) = default;
// Shallow copy by default. Call \ref CopyFrom for a deep copy
void operator=(const Blob& rhs) {
this->data_ = rhs.data_;
this->size_ = rhs.size_;
}
char operator[](size_t i) const {
CHECK(0 <= i && i < size_);
return data_.get()[i];
}
template <typename T>
T& As(size_t i = 0) const {
CHECK(size_ % sizeof(T) == 0 && i < size_ / sizeof(T));
return (reinterpret_cast<T*>(data_.get()))[i];
}
template <typename T>
size_t size() const { return size_ / sizeof(T); }
// DeepCopy, for a shallow copy, use operator=
void CopyFrom(const Blob& src);
char* data() const { return data_.get(); }
size_t size() const { return size_; }
private:
// Memory is shared and auto managed
std::shared_ptr<char> data_;
size_t size_;
};
}
#ifndef MULTIVERSO_BLOB_H_
#define MULTIVERSO_BLOB_H_
#include <memory>
#include <string>
#include "log.h"
namespace multiverso {
// Manage a chunk of memory. Blob can share memory with other Blobs.
// Never use external memory. All external memory should be managed by itself
class Blob {
public:
// an empty blob
Blob() {};
explicit Blob(size_t size) : size_(size) {
CHECK(size > 0);
data_.reset(new char[size]);
}
// Construct from external memory. Will copy a new piece
Blob(void* data, size_t size) : size_(size) {
data_.reset(new char[size]);
memcpy(data_.get(), data, size_);
}
Blob(const Blob&) = default;
// Shallow copy by default. Call \ref CopyFrom for a deep copy
void operator=(const Blob& rhs) {
this->data_ = rhs.data_;
this->size_ = rhs.size_;
}
char operator[](size_t i) const {
CHECK(0 <= i && i < size_);
return data_.get()[i];
}
template <typename T>
T& As(size_t i = 0) const {
CHECK(size_ % sizeof(T) == 0 && i < size_ / sizeof(T));
return (reinterpret_cast<T*>(data_.get()))[i];
}
template <typename T>
size_t size() const { return size_ / sizeof(T); }
// DeepCopy, for a shallow copy, use operator=
void CopyFrom(const Blob& src);
char* data() const { return data_.get(); }
size_t size() const { return size_; }
private:
// Memory is shared and auto managed
std::shared_ptr<char> data_;
size_t size_;
};
}
#endif // MULTIVERSO_BLOB_H_

Просмотреть файл

@ -1,69 +1,69 @@
#include "communicator.h"
#include "zoo.h"
#include "net.h"
#include "log.h"
namespace multiverso {
namespace message {
// TODO(feiga): refator the ugly statement
bool to_server(MsgType type) {
return (static_cast<int>(type)) > 0 &&
(static_cast<int>(type)) < 32;
}
bool to_worker(MsgType type) {
return (static_cast<int>(type)) < 0 &&
(static_cast<int>(type)) > -32;
}
bool to_controler(MsgType type) {
return (static_cast<int>(type)) > 32;
}
}
Communicator::Communicator() : Actor(actor::kCommunicator) {
RegisterTask(MsgType::Default, std::bind(
&Communicator::ProcessMessage, this, std::placeholders::_1));
net_util_ = NetInterface::Get();
}
void Communicator::Main() {
// TODO(feiga): join the thread, make sure it exit properly
recv_thread_.reset(new std::thread(&Communicator::Communicate, this));
Actor::Main();
}
void Communicator::ProcessMessage(MessagePtr& msg) {
if (msg->dst() != net_util_->rank()) {
net_util_->Send(msg);
return;
}
LocalForward(msg);
}
void Communicator::Communicate() {
while (true) { // TODO(feiga): should exit properly
MessagePtr msg = std::make_unique<Message>();
if (!net_util_->Recv(&msg)) break;
CHECK(msg->dst() == Zoo::Get()->rank());
LocalForward(msg);
}
Log::Info("Comm recv thread exit\n");
}
void Communicator::LocalForward(MessagePtr& msg) {
CHECK(msg->dst() == Zoo::Get()->rank());
if (message::to_server(msg->type())) {
DeliverTo(actor::kServer, msg);
} else if (message::to_worker(msg->type())) {
DeliverTo(actor::kWorker, msg);
} else if (message::to_controler(msg->type())) {
DeliverTo(actor::kController, msg);
} else {
// Send back to the msg queue of zoo
Zoo::Get()->Accept(msg);
}
}
#include "communicator.h"
#include "zoo.h"
#include "net.h"
#include "log.h"
namespace multiverso {
namespace message {
// TODO(feiga): refator the ugly statement
bool to_server(MsgType type) {
return (static_cast<int>(type)) > 0 &&
(static_cast<int>(type)) < 32;
}
bool to_worker(MsgType type) {
return (static_cast<int>(type)) < 0 &&
(static_cast<int>(type)) > -32;
}
bool to_controler(MsgType type) {
return (static_cast<int>(type)) > 32;
}
}
Communicator::Communicator() : Actor(actor::kCommunicator) {
RegisterTask(MsgType::Default, std::bind(
&Communicator::ProcessMessage, this, std::placeholders::_1));
net_util_ = NetInterface::Get();
}
void Communicator::Main() {
// TODO(feiga): join the thread, make sure it exit properly
recv_thread_.reset(new std::thread(&Communicator::Communicate, this));
Actor::Main();
}
void Communicator::ProcessMessage(MessagePtr& msg) {
if (msg->dst() != net_util_->rank()) {
net_util_->Send(msg);
return;
}
LocalForward(msg);
}
void Communicator::Communicate() {
while (true) { // TODO(feiga): should exit properly
MessagePtr msg = std::make_unique<Message>();
if (!net_util_->Recv(&msg)) break;
CHECK(msg->dst() == Zoo::Get()->rank());
LocalForward(msg);
}
Log::Info("Comm recv thread exit\n");
}
void Communicator::LocalForward(MessagePtr& msg) {
CHECK(msg->dst() == Zoo::Get()->rank());
if (message::to_server(msg->type())) {
DeliverTo(actor::kServer, msg);
} else if (message::to_worker(msg->type())) {
DeliverTo(actor::kWorker, msg);
} else if (message::to_controler(msg->type())) {
DeliverTo(actor::kController, msg);
} else {
// Send back to the msg queue of zoo
Zoo::Get()->Accept(msg);
}
}
}

Просмотреть файл

@ -1,30 +1,30 @@
#ifndef MULTIVERSO_COMMUNICATION_H_
#define MULTIVERSO_COMMUNICATION_H_
#include "actor.h"
#include "message.h"
namespace multiverso {
class NetInterface;
class Communicator : public Actor {
public:
Communicator();
~Communicator() {}
private:
void Main() override;
// Process message received from other actors, either send to other nodes, or
// forward to local actors.
void ProcessMessage(MessagePtr& msg);
// Thread function to receive messages from other nodes
void Communicate();
// Forward to other actors in the same node
void LocalForward(MessagePtr& msg);
NetInterface* net_util_;
std::unique_ptr<std::thread> recv_thread_;
};
}
#ifndef MULTIVERSO_COMMUNICATION_H_
#define MULTIVERSO_COMMUNICATION_H_
#include "actor.h"
#include "message.h"
namespace multiverso {
class NetInterface;
class Communicator : public Actor {
public:
Communicator();
~Communicator() {}
private:
void Main() override;
// Process message received from other actors, either send to other nodes, or
// forward to local actors.
void ProcessMessage(MessagePtr& msg);
// Thread function to receive messages from other nodes
void Communicate();
// Forward to other actors in the same node
void LocalForward(MessagePtr& msg);
NetInterface* net_util_;
std::unique_ptr<std::thread> recv_thread_;
};
}
#endif // MULTIVERSO_COMMUNICATION_H_

Просмотреть файл

@ -1,43 +1,43 @@
#include "controller.h"
#include "message.h"
#include "zoo.h"
namespace multiverso {
class Controller::BarrierController {
public:
explicit BarrierController(Controller* parent) : parent_(parent) {}
void Control(MessagePtr& msg) {
tasks_.push_back(std::move(msg));
if (tasks_.size() == Zoo::Get()->size()) {
MessagePtr my_reply; // my reply should be the last one
for (auto& msg : tasks_) {
MessagePtr reply(msg->CreateReplyMessage());
if (reply->dst() != Zoo::Get()->rank()) {
parent_->DeliverTo(actor::kCommunicator, reply);
} else {
my_reply = std::move(reply);
}
}
parent_->DeliverTo(actor::kCommunicator, my_reply);
tasks_.clear();
}
}
private:
std::vector<MessagePtr> tasks_;
Controller* parent_; // not owned
};
Controller::Controller() : Actor(actor::kController) {
RegisterTask(MsgType::Control_Barrier, std::bind(
&Controller::ProcessBarrier, this, std::placeholders::_1));
barrier_controller_ = new BarrierController(this);
}
void Controller::ProcessBarrier(MessagePtr& msg) {
barrier_controller_->Control(msg);
}
#include "controller.h"
#include "message.h"
#include "zoo.h"
namespace multiverso {
class Controller::BarrierController {
public:
explicit BarrierController(Controller* parent) : parent_(parent) {}
void Control(MessagePtr& msg) {
tasks_.push_back(std::move(msg));
if (tasks_.size() == Zoo::Get()->size()) {
MessagePtr my_reply; // my reply should be the last one
for (auto& msg : tasks_) {
MessagePtr reply(msg->CreateReplyMessage());
if (reply->dst() != Zoo::Get()->rank()) {
parent_->DeliverTo(actor::kCommunicator, reply);
} else {
my_reply = std::move(reply);
}
}
parent_->DeliverTo(actor::kCommunicator, my_reply);
tasks_.clear();
}
}
private:
std::vector<MessagePtr> tasks_;
Controller* parent_; // not owned
};
Controller::Controller() : Actor(actor::kController) {
RegisterTask(MsgType::Control_Barrier, std::bind(
&Controller::ProcessBarrier, this, std::placeholders::_1));
barrier_controller_ = new BarrierController(this);
}
void Controller::ProcessBarrier(MessagePtr& msg) {
barrier_controller_->Control(msg);
}
}

Просмотреть файл

@ -1,24 +1,24 @@
#ifndef MULTIVERSO_CONTROLLER_H_
#define MULTIVERSO_CONTROLLER_H_
#include "actor.h"
#include "message.h"
namespace multiverso {
class Controller : public Actor {
public:
Controller();
private:
void ProcessBarrier(MessagePtr& msg);
// TODO(feiga): may delete the following
class BarrierController;
BarrierController* barrier_controller_;
class ClockController;
ClockController* clock_controller_;
};
} // namespace multiverso
#ifndef MULTIVERSO_CONTROLLER_H_
#define MULTIVERSO_CONTROLLER_H_
#include "actor.h"
#include "message.h"
namespace multiverso {
class Controller : public Actor {
public:
Controller();
private:
void ProcessBarrier(MessagePtr& msg);
// TODO(feiga): may delete the following
class BarrierController;
BarrierController* barrier_controller_;
class ClockController;
ClockController* clock_controller_;
};
} // namespace multiverso
#endif // MULTIVERSO_CONTROLLER_H_

210
next/IMultiverso/new/kv_table.h → next/new/kv_table.h Executable file → Normal file
Просмотреть файл

@ -1,106 +1,106 @@
#ifndef MULTIVERSO_KV_TABLE_H_
#define MULTIVERSO_KV_TABLE_H_
#include "table_interface.h"
#include "log.h"
#include "zoo.h"
#include <unordered_map>
#include <vector>
namespace multiverso {
// A distributed shared std::unordered_map<Key, Val> table
// Key, Val should be the basic type
template <typename Key, typename Val>
class KVWorkerTable : public WorkerTable {
public:
void Get(Key key) { WorkerTable::Get(Blob(&key, sizeof(Key))); }
void Get(std::vector<Key>& keys) {
WorkerTable::Get(Blob(&keys[0], sizeof(Key) * keys.size()));
}
void Add(Key key, Val value) {
WorkerTable::Add(Blob(&key, sizeof(Key)), Blob(&value, sizeof(Val)));
}
void Add(std::vector<Key>& keys, std::vector<Val>& vals) {
CHECK(keys.size() == vals.size());
Blob keys_blob(&keys[0], sizeof(Key) * keys.size());
Blob vals_blob(&vals[0], sizeof(Val) * vals.size());
WorkerTable::Add(keys_blob, vals_blob);
}
std::unordered_map<Key, Val>& raw() { return table_; }
int Partition(const std::vector<Blob>& kv,
std::unordered_map<int, std::vector<Blob> >* out) override {
CHECK(kv.size() == 1 || kv.size() == 2);
CHECK_NOTNULL(out);
std::unordered_map<int, int> counts;
Blob keys = kv[0];
for (int i = 0; i < keys.size<Key>(); ++i) { // iterate as type Key
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
++counts[dst];
}
for (auto& it : counts) { // Allocate memory
std::vector<Blob>& vec = (*out)[it.first];
vec.push_back(Blob(it.second * sizeof(Key)));
if (kv.size() == 2) vec.push_back(Blob(it.second * sizeof(Val)));
}
counts.clear();
for (int i = 0; i < keys.size<Key>(); ++i) {
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
(*out)[dst][0].As<Key>(counts[dst]) = keys.As<Key>(i);
if (kv.size() == 2)
(*out)[dst][1].As<Val>(counts[dst]) = kv[1].As<Val>(i);
}
return static_cast<int>(out->size());
}
void ProcessReplyGet(std::vector<Blob>& data) override {
CHECK(data.size() == 2);
Blob keys = data[0], vals = data[1];
CHECK(keys.size<Key>() == vals.size<Val>());
for (int i = 0; i < keys.size<Key>(); ++i) {
table_[keys.As<Key>(i)] = vals.As<Val>(i);
}
}
private:
std::unordered_map<Key, Val> table_;
};
template <typename Key, typename Val>
class KVServerTable : public ServerTable {
public:
void ProcessGet(const std::vector<Blob>& data,
std::vector<Blob>* result) override {
CHECK(data.size() == 1);
CHECK_NOTNULL(result);
Blob keys = data[0];
result->push_back(keys); // also push the key
result->push_back(Blob(keys.size<Key>() * sizeof(Val)));
Blob& vals = (*result)[1];
for (int i = 0; i < keys.size<Key>(); ++i) {
vals.As<Val>(i) = table_[keys.As<Key>(i)];
}
}
void ProcessAdd(const std::vector<Blob>& data) override {
CHECK(data.size() == 2);
Blob keys = data[0], vals = data[1];
CHECK(keys.size<Key>() == vals.size<Val>());
for (int i = 0; i < keys.size<Key>(); ++i) {
table_[keys.As<Key>(i)] += vals.As<Val>(i);
}
}
private:
std::unordered_map<Key, Val> table_;
};
}
#ifndef MULTIVERSO_KV_TABLE_H_
#define MULTIVERSO_KV_TABLE_H_
#include "table_interface.h"
#include "log.h"
#include "zoo.h"
#include <unordered_map>
#include <vector>
namespace multiverso {
// A distributed shared std::unordered_map<Key, Val> table
// Key, Val should be the basic type
template <typename Key, typename Val>
class KVWorkerTable : public WorkerTable {
public:
void Get(Key key) { WorkerTable::Get(Blob(&key, sizeof(Key))); }
void Get(std::vector<Key>& keys) {
WorkerTable::Get(Blob(&keys[0], sizeof(Key) * keys.size()));
}
void Add(Key key, Val value) {
WorkerTable::Add(Blob(&key, sizeof(Key)), Blob(&value, sizeof(Val)));
}
void Add(std::vector<Key>& keys, std::vector<Val>& vals) {
CHECK(keys.size() == vals.size());
Blob keys_blob(&keys[0], sizeof(Key) * keys.size());
Blob vals_blob(&vals[0], sizeof(Val) * vals.size());
WorkerTable::Add(keys_blob, vals_blob);
}
std::unordered_map<Key, Val>& raw() { return table_; }
int Partition(const std::vector<Blob>& kv,
std::unordered_map<int, std::vector<Blob> >* out) override {
CHECK(kv.size() == 1 || kv.size() == 2);
CHECK_NOTNULL(out);
std::unordered_map<int, int> counts;
Blob keys = kv[0];
for (int i = 0; i < keys.size<Key>(); ++i) { // iterate as type Key
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
++counts[dst];
}
for (auto& it : counts) { // Allocate memory
std::vector<Blob>& vec = (*out)[it.first];
vec.push_back(Blob(it.second * sizeof(Key)));
if (kv.size() == 2) vec.push_back(Blob(it.second * sizeof(Val)));
}
counts.clear();
for (int i = 0; i < keys.size<Key>(); ++i) {
int dst = static_cast<int>(keys.As<Key>(i) % Zoo::Get()->num_servers());
(*out)[dst][0].As<Key>(counts[dst]) = keys.As<Key>(i);
if (kv.size() == 2)
(*out)[dst][1].As<Val>(counts[dst]) = kv[1].As<Val>(i);
}
return static_cast<int>(out->size());
}
void ProcessReplyGet(std::vector<Blob>& data) override {
CHECK(data.size() == 2);
Blob keys = data[0], vals = data[1];
CHECK(keys.size<Key>() == vals.size<Val>());
for (int i = 0; i < keys.size<Key>(); ++i) {
table_[keys.As<Key>(i)] = vals.As<Val>(i);
}
}
private:
std::unordered_map<Key, Val> table_;
};
template <typename Key, typename Val>
class KVServerTable : public ServerTable {
public:
void ProcessGet(const std::vector<Blob>& data,
std::vector<Blob>* result) override {
CHECK(data.size() == 1);
CHECK_NOTNULL(result);
Blob keys = data[0];
result->push_back(keys); // also push the key
result->push_back(Blob(keys.size<Key>() * sizeof(Val)));
Blob& vals = (*result)[1];
for (int i = 0; i < keys.size<Key>(); ++i) {
vals.As<Val>(i) = table_[keys.As<Key>(i)];
}
}
void ProcessAdd(const std::vector<Blob>& data) override {
CHECK(data.size() == 2);
Blob keys = data[0], vals = data[1];
CHECK(keys.size<Key>() == vals.size<Val>());
for (int i = 0; i < keys.size<Key>(); ++i) {
table_[keys.As<Key>(i)] += vals.As<Val>(i);
}
}
private:
std::unordered_map<Key, Val> table_;
};
}
#endif // MULTIVERSO_KV_TABLE_H_

370
next/IMultiverso/new/log.cpp → next/new/log.cpp Executable file → Normal file
Просмотреть файл

@ -1,185 +1,185 @@
#include <ctime>
#include <cstdarg>
#include "log.h"
namespace multiverso
{
//-- Begin of Logger rountine --------------------------------------------/
// Creates a Logger intance writing messages into STDOUT.
Logger::Logger(LogLevel level) {
level_ = level;
file_ = nullptr;
is_kill_fatal_ = true;
}
// Creates a Logger instance writing messages into both STDOUT and log file.
Logger::Logger(std::string filename, LogLevel level) {
level_ = level;
file_ = nullptr;
ResetLogFile(filename);
}
Logger::~Logger() {
CloseLogFile();
}
int Logger::ResetLogFile(std::string filename) {
CloseLogFile();
if (filename.size() > 0) // try to open the log file if it is specified
{
#ifdef _MSC_VER
fopen_s(&file_, filename.c_str(), "w");
#elif
file_ = fopen(filename.c_str(), "w");
#endif
if (file_ == nullptr) {
Error("Cannot create log file %s\n", filename.c_str());
return -1;
}
}
return 0;
}
void Logger::Write(LogLevel level, const char *format, ...) {
va_list val;
va_start(val, format);
Write(level, format, val);
va_end(val);
}
void Logger::Debug(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Debug, format, val);
va_end(val);
}
void Logger::Info(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Info, format, val);
va_end(val);
}
void Logger::Error(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Error, format, val);
va_end(val);
}
void Logger::Fatal(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Fatal, format, val);
va_end(val);
}
inline void Logger::Write(LogLevel level, const char *format, va_list &val) {
if (level >= level_) // omit the message with low level
{
std::string level_str = GetLevelStr(level);
std::string time_str = GetSystemTime();
va_list val_copy;
va_copy(val_copy, val);
// write to STDOUT
printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
vprintf(format, val);
fflush(stdout);
// write to log file
if (file_ != nullptr) {
fprintf(file_, "[%s] [%s] ", level_str.c_str(), time_str.c_str());
vfprintf(file_, format, val_copy);
fflush(file_);
}
va_end(val_copy);
if (is_kill_fatal_ && level == LogLevel::Fatal) {
CloseLogFile();
exit(1);
}
}
}
// Closes the log file if it it not null.
void Logger::CloseLogFile() {
if (file_ != nullptr) {
fclose(file_);
file_ = nullptr;
}
}
std::string Logger::GetSystemTime() {
time_t t = time(0);
char str[64];
#ifdef _MSC_VER
tm time;
localtime_s(&time, &t);
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time);
#elif
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
#endif
return str;
}
std::string Logger::GetLevelStr(LogLevel level) {
switch (level) {
case LogLevel::Debug: return "DEBUG";
case LogLevel::Info: return "INFO";
case LogLevel::Error: return "ERROR";
case LogLevel::Fatal: return "FATAL";
default: return "UNKNOW";
}
}
//-- End of Logger rountine ----------------------------------------------/
Logger Log::logger_; // global (in process) static Logger instance
int Log::ResetLogFile(std::string filename) {
return logger_.ResetLogFile(filename);
}
void Log::ResetLogLevel(LogLevel level) {
logger_.ResetLogLevel(level);
}
void Log::ResetKillFatal(bool is_kill_fatal) {
logger_.ResetKillFatal(is_kill_fatal);
}
void Log::Write(LogLevel level, const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(level, format, val);
va_end(val);
}
void Log::Debug(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Debug, format, val);
va_end(val);
}
void Log::Info(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Info, format, val);
va_end(val);
}
void Log::Error(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Error, format, val);
va_end(val);
}
void Log::Fatal(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Fatal, format, val);
va_end(val);
}
}
#include <ctime>
#include <cstdarg>
#include "log.h"
namespace multiverso
{
//-- Begin of Logger rountine --------------------------------------------/
// Creates a Logger intance writing messages into STDOUT.
Logger::Logger(LogLevel level) {
level_ = level;
file_ = nullptr;
is_kill_fatal_ = true;
}
// Creates a Logger instance writing messages into both STDOUT and log file.
Logger::Logger(std::string filename, LogLevel level) {
level_ = level;
file_ = nullptr;
ResetLogFile(filename);
}
Logger::~Logger() {
CloseLogFile();
}
int Logger::ResetLogFile(std::string filename) {
CloseLogFile();
if (filename.size() > 0) // try to open the log file if it is specified
{
#ifdef _MSC_VER
fopen_s(&file_, filename.c_str(), "w");
#elif
file_ = fopen(filename.c_str(), "w");
#endif
if (file_ == nullptr) {
Error("Cannot create log file %s\n", filename.c_str());
return -1;
}
}
return 0;
}
void Logger::Write(LogLevel level, const char *format, ...) {
va_list val;
va_start(val, format);
Write(level, format, val);
va_end(val);
}
void Logger::Debug(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Debug, format, val);
va_end(val);
}
void Logger::Info(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Info, format, val);
va_end(val);
}
void Logger::Error(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Error, format, val);
va_end(val);
}
void Logger::Fatal(const char *format, ...) {
va_list val;
va_start(val, format);
Write(LogLevel::Fatal, format, val);
va_end(val);
}
inline void Logger::Write(LogLevel level, const char *format, va_list &val) {
if (level >= level_) // omit the message with low level
{
std::string level_str = GetLevelStr(level);
std::string time_str = GetSystemTime();
va_list val_copy;
va_copy(val_copy, val);
// write to STDOUT
printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
vprintf(format, val);
fflush(stdout);
// write to log file
if (file_ != nullptr) {
fprintf(file_, "[%s] [%s] ", level_str.c_str(), time_str.c_str());
vfprintf(file_, format, val_copy);
fflush(file_);
}
va_end(val_copy);
if (is_kill_fatal_ && level == LogLevel::Fatal) {
CloseLogFile();
exit(1);
}
}
}
// Closes the log file if it it not null.
void Logger::CloseLogFile() {
if (file_ != nullptr) {
fclose(file_);
file_ = nullptr;
}
}
std::string Logger::GetSystemTime() {
time_t t = time(0);
char str[64];
#ifdef _MSC_VER
tm time;
localtime_s(&time, &t);
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time);
#elif
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
#endif
return str;
}
std::string Logger::GetLevelStr(LogLevel level) {
switch (level) {
case LogLevel::Debug: return "DEBUG";
case LogLevel::Info: return "INFO";
case LogLevel::Error: return "ERROR";
case LogLevel::Fatal: return "FATAL";
default: return "UNKNOW";
}
}
//-- End of Logger rountine ----------------------------------------------/
Logger Log::logger_; // global (in process) static Logger instance
int Log::ResetLogFile(std::string filename) {
return logger_.ResetLogFile(filename);
}
void Log::ResetLogLevel(LogLevel level) {
logger_.ResetLogLevel(level);
}
void Log::ResetKillFatal(bool is_kill_fatal) {
logger_.ResetKillFatal(is_kill_fatal);
}
void Log::Write(LogLevel level, const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(level, format, val);
va_end(val);
}
void Log::Debug(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Debug, format, val);
va_end(val);
}
void Log::Info(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Info, format, val);
va_end(val);
}
void Log::Error(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Error, format, val);
va_end(val);
}
void Log::Fatal(const char *format, ...) {
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Fatal, format, val);
va_end(val);
}
}

300
next/IMultiverso/new/log.h → next/new/log.h Executable file → Normal file
Просмотреть файл

@ -1,150 +1,150 @@
#ifndef MULTIVERSO_LOG_H_
#define MULTIVERSO_LOG_H_
/*!
* \file log.h
* \brief Provides simple logging tools.
*/
#include <fstream>
#include <string>
namespace multiverso
{
#define CHECK(condition) \
if (!(condition)) Log::Fatal("Check failed: " #condition " \n");
#define CHECK_NOTNULL(pointer) \
if ((pointer) == nullptr) Log::Fatal(#pointer " Must be non NULL\n");
/*!
* \brief A enumeration type of log message levels. The values are ordered:
* Debug < Info < Error < Fatal.
*/
enum class LogLevel : int
{
Debug = 0,
Info = 1,
Error = 2,
Fatal = 3
};
/*!
* \brief The Logger class is responsible for writing log messages into
* standard output or log file.
*/
class Logger
{
// Enable the static Log class to call the private method.
friend class Log;
public:
/*!
* \brief Creates an instance of Logger class. By default, the log
* messages will be written to standard output with minimal
* level of INFO. Users are able to further set the log file or
* log level with corresponding methods.
* \param level Minimal log level, Info by default.
*/
explicit Logger(LogLevel level = LogLevel::Info);
/*!
* \brief Creates an instance of Logger class by specifying log file
* and log level. The log message will be written to both STDOUT
* and file (if created successfully).
* \param filename Log file name
* \param level Minimal log level
*/
explicit Logger(std::string filename, LogLevel level = LogLevel::Info);
~Logger();
/*!
* \brief Resets the log file.
* \param filename The new log filename. If it is empty, the Logger
* will close current log file (if it exists).
* \return Returns -1 if the filename is not empty but failed on
* creating the log file, or 0 will be returned otherwise.
*/
int ResetLogFile(std::string filename);
/*!
* \brief Resets the log level.
* \param level The new log level.
*/
void ResetLogLevel(LogLevel level) { level_ = level; }
/*!
* \brief Resets the option of whether kill the process when fatal
* error occurs. By defualt the option is false.
*/
void ResetKillFatal(bool is_kill_fatal) { is_kill_fatal_ = is_kill_fatal; }
/*!
* \brief C style formatted method for writing log messages. A message
* is with the following format: [LEVEL] [TIME] message
* \param level The log level of this message.
* \param format The C format string.
* \param ... Output items.
*/
void Write(LogLevel level, const char *format, ...);
void Debug(const char *format, ...);
void Info(const char *format, ...);
void Error(const char *format, ...);
void Fatal(const char *format, ...);
private:
void Write(LogLevel level, const char *format, va_list &val);
void CloseLogFile();
// Returns current system time as a string.
std::string GetSystemTime();
// Returns the string of a log level.
std::string GetLevelStr(LogLevel level);
std::FILE *file_; // A file pointer to the log file.
LogLevel level_; // Only the message not less than level_ will be outputed.
bool is_kill_fatal_; // If kill the process when fatal error occurs.
// No copying allowed
Logger(const Logger&);
void operator=(const Logger&);
};
/*!
* \brief The Log class is a static wrapper of a global Logger instance in
* the scope of a process. Users can write logging messages easily
* with the static methods.
*/
class Log
{
public:
/*!
* \brief Resets the log file. The logger will write messages to the
* log file if it exists in addition to the STDOUT by default.
* \param filename The log filename. If it is empty, the logger will
* close the current log file (if it exists) and only output to
* STDOUT.
* \return -1 if fail on creating the log file, or 0 otherwise.
*/
static int ResetLogFile(std::string filename);
/*!
* \brief Resets the minimal log level. It is INFO by default.
* \param level The new minimal log level.
*/
static void ResetLogLevel(LogLevel level);
/*!
* \brief Resets the option of whether kill the process when fatal
* error occurs. By defualt the option is false.
*/
static void ResetKillFatal(bool is_kill_fatal);
/*! \brief The C formatted methods of writing the messages. */
static void Write(LogLevel level, const char *format, ...);
static void Debug(const char *format, ...);
static void Info(const char *format, ...);
static void Error(const char *format, ...);
static void Fatal(const char *format, ...);
private:
static Logger logger_;
};
}
#endif // MULTIVERSO_LOG_H_
#ifndef MULTIVERSO_LOG_H_
#define MULTIVERSO_LOG_H_
/*!
* \file log.h
* \brief Provides simple logging tools.
*/
#include <fstream>
#include <string>
namespace multiverso
{
#define CHECK(condition) \
if (!(condition)) Log::Fatal("Check failed: " #condition " \n");
#define CHECK_NOTNULL(pointer) \
if ((pointer) == nullptr) Log::Fatal(#pointer " Must be non NULL\n");
/*!
* \brief A enumeration type of log message levels. The values are ordered:
* Debug < Info < Error < Fatal.
*/
enum class LogLevel : int
{
Debug = 0,
Info = 1,
Error = 2,
Fatal = 3
};
/*!
* \brief The Logger class is responsible for writing log messages into
* standard output or log file.
*/
class Logger
{
// Enable the static Log class to call the private method.
friend class Log;
public:
/*!
* \brief Creates an instance of Logger class. By default, the log
* messages will be written to standard output with minimal
* level of INFO. Users are able to further set the log file or
* log level with corresponding methods.
* \param level Minimal log level, Info by default.
*/
explicit Logger(LogLevel level = LogLevel::Info);
/*!
* \brief Creates an instance of Logger class by specifying log file
* and log level. The log message will be written to both STDOUT
* and file (if created successfully).
* \param filename Log file name
* \param level Minimal log level
*/
explicit Logger(std::string filename, LogLevel level = LogLevel::Info);
~Logger();
/*!
* \brief Resets the log file.
* \param filename The new log filename. If it is empty, the Logger
* will close current log file (if it exists).
* \return Returns -1 if the filename is not empty but failed on
* creating the log file, or 0 will be returned otherwise.
*/
int ResetLogFile(std::string filename);
/*!
* \brief Resets the log level.
* \param level The new log level.
*/
void ResetLogLevel(LogLevel level) { level_ = level; }
/*!
* \brief Resets the option of whether kill the process when fatal
* error occurs. By defualt the option is false.
*/
void ResetKillFatal(bool is_kill_fatal) { is_kill_fatal_ = is_kill_fatal; }
/*!
* \brief C style formatted method for writing log messages. A message
* is with the following format: [LEVEL] [TIME] message
* \param level The log level of this message.
* \param format The C format string.
* \param ... Output items.
*/
void Write(LogLevel level, const char *format, ...);
void Debug(const char *format, ...);
void Info(const char *format, ...);
void Error(const char *format, ...);
void Fatal(const char *format, ...);
private:
void Write(LogLevel level, const char *format, va_list &val);
void CloseLogFile();
// Returns current system time as a string.
std::string GetSystemTime();
// Returns the string of a log level.
std::string GetLevelStr(LogLevel level);
std::FILE *file_; // A file pointer to the log file.
LogLevel level_; // Only the message not less than level_ will be outputed.
bool is_kill_fatal_; // If kill the process when fatal error occurs.
// No copying allowed
Logger(const Logger&);
void operator=(const Logger&);
};
/*!
* \brief The Log class is a static wrapper of a global Logger instance in
* the scope of a process. Users can write logging messages easily
* with the static methods.
*/
class Log
{
public:
/*!
* \brief Resets the log file. The logger will write messages to the
* log file if it exists in addition to the STDOUT by default.
* \param filename The log filename. If it is empty, the logger will
* close the current log file (if it exists) and only output to
* STDOUT.
* \return -1 if fail on creating the log file, or 0 otherwise.
*/
static int ResetLogFile(std::string filename);
/*!
* \brief Resets the minimal log level. It is INFO by default.
* \param level The new minimal log level.
*/
static void ResetLogLevel(LogLevel level);
/*!
* \brief Resets the option of whether kill the process when fatal
* error occurs. By defualt the option is false.
*/
static void ResetKillFatal(bool is_kill_fatal);
/*! \brief The C formatted methods of writing the messages. */
static void Write(LogLevel level, const char *format, ...);
static void Debug(const char *format, ...);
static void Info(const char *format, ...);
static void Error(const char *format, ...);
static void Fatal(const char *format, ...);
private:
static Logger logger_;
};
}
#endif // MULTIVERSO_LOG_H_

168
next/IMultiverso/new/message.h → next/new/message.h Executable file → Normal file
Просмотреть файл

@ -1,85 +1,85 @@
#ifndef MULTIVERSO_MESSAGE_H_
#define MULTIVERSO_MESSAGE_H_
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "blob.h"
#include "log.h"
namespace multiverso {
enum class MsgType : int {
Request_Get = 1,
Request_Add = 2,
Reply_Get = -1,
Reply_Add = -2,
Control_Barrier = 33, // 0x100001
Control_Reply_Barrier = -33,
Default = 0
};
// using DoneCallBack = std::function<void()>;
class Message {
public:
Message() { }
~Message() { }
MsgType type() const { return static_cast<MsgType>(header_[2]); }
int src() const { return header_[0]; }
int dst() const { return header_[1]; }
int table_id() const { return header_[3]; }
int msg_id() const { return header_[4]; }
void set_type(MsgType type) { header_[2] = static_cast<int>(type); }
void set_src(int src) { header_[0] = src; }
void set_dst(int dst) { header_[1] = dst; }
void set_table_id(int table_id) { header_[3] = table_id; }
void set_msg_id(int msg_id) { header_[4] = msg_id; }
// DoneCallBack done() { return done_; }
// void set_done(DoneCallBack& done) { done_ = done; }
void set_data(const std::vector<Blob>& data) { data_ = std::move(data); }
std::vector<Blob>& data() { return data_; }
size_t size() const { return data_.size(); }
int* header() { return header_; }
const int* header() const { return header_; }
static const int kHeaderSize = 8 * sizeof(int);
// Deep Copy
Message* CopyFrom(const Message& src);
// Create a Message with only headers
// The src/dst, type is opposite with src message
Message* CreateReplyMessage() {
Message* reply = new Message();
reply->set_dst(this->src());
reply->set_src(this->dst());
reply->set_type(static_cast<MsgType>(-header_[2]));
reply->set_table_id(this->table_id());
reply->set_msg_id(this->msg_id());
return reply;
}
void Push(const Blob& blob) { data_.push_back(blob); }
void DebugString() {
Log::Info("msg header: src = %d, dst = %d, type = %d, table = %d, id = %d, data_size = %d",
src(), dst(), type(), table_id(), msg_id(), data_.size());
}
private:
int header_[8];
std::vector<Blob> data_;
// DoneCallBack done_; // only use in worker
};
typedef std::unique_ptr<Message> MessagePtr;
}
#ifndef MULTIVERSO_MESSAGE_H_
#define MULTIVERSO_MESSAGE_H_
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "blob.h"
#include "log.h"
namespace multiverso {
enum class MsgType : int {
Request_Get = 1,
Request_Add = 2,
Reply_Get = -1,
Reply_Add = -2,
Control_Barrier = 33, // 0x100001
Control_Reply_Barrier = -33,
Default = 0
};
// using DoneCallBack = std::function<void()>;
class Message {
public:
Message() { }
~Message() { }
MsgType type() const { return static_cast<MsgType>(header_[2]); }
int src() const { return header_[0]; }
int dst() const { return header_[1]; }
int table_id() const { return header_[3]; }
int msg_id() const { return header_[4]; }
void set_type(MsgType type) { header_[2] = static_cast<int>(type); }
void set_src(int src) { header_[0] = src; }
void set_dst(int dst) { header_[1] = dst; }
void set_table_id(int table_id) { header_[3] = table_id; }
void set_msg_id(int msg_id) { header_[4] = msg_id; }
// DoneCallBack done() { return done_; }
// void set_done(DoneCallBack& done) { done_ = done; }
void set_data(const std::vector<Blob>& data) { data_ = std::move(data); }
std::vector<Blob>& data() { return data_; }
size_t size() const { return data_.size(); }
int* header() { return header_; }
const int* header() const { return header_; }
static const int kHeaderSize = 8 * sizeof(int);
// Deep Copy
Message* CopyFrom(const Message& src);
// Create a Message with only headers
// The src/dst, type is opposite with src message
Message* CreateReplyMessage() {
Message* reply = new Message();
reply->set_dst(this->src());
reply->set_src(this->dst());
reply->set_type(static_cast<MsgType>(-header_[2]));
reply->set_table_id(this->table_id());
reply->set_msg_id(this->msg_id());
return reply;
}
void Push(const Blob& blob) { data_.push_back(blob); }
void DebugString() {
Log::Info("msg header: src = %d, dst = %d, type = %d, table = %d, id = %d, data_size = %d",
src(), dst(), type(), table_id(), msg_id(), data_.size());
}
private:
int header_[8];
std::vector<Blob> data_;
// DoneCallBack done_; // only use in worker
};
typedef std::unique_ptr<Message> MessagePtr;
}
#endif // MULTIVERSO_MESSAGE_H_

Просмотреть файл

Просмотреть файл

@ -1,19 +1,19 @@
#include "multiverso.h"
#include "zoo.h"
namespace multiverso {
void MultiversoInit() {
Zoo::Get()->Start();
}
void MultiversoShutDown() {
Zoo::Get()->Stop();
}
void MultiversoBarrier() {
Zoo::Get()->Barrier();
}
}
#include "multiverso.h"
#include "zoo.h"
namespace multiverso {
void MultiversoInit() {
Zoo::Get()->Start();
}
void MultiversoShutDown() {
Zoo::Get()->Stop();
}
void MultiversoBarrier() {
Zoo::Get()->Barrier();
}
}

Просмотреть файл

@ -1,14 +1,14 @@
#ifndef MULTIVERSO_INCLUDE_MULTIVERSO_H_
#define MULTIVERSO_INCLUDE_MULTIVERSO_H_
namespace multiverso {
void MultiversoInit();
void MultiversoBarrier();
void MultiversoShutDown();
}
#ifndef MULTIVERSO_INCLUDE_MULTIVERSO_H_
#define MULTIVERSO_INCLUDE_MULTIVERSO_H_
namespace multiverso {
void MultiversoInit();
void MultiversoBarrier();
void MultiversoShutDown();
}
#endif // MULTIVERSO_INCLUDE_MULTIVERSO_H_

198
next/IMultiverso/new/net.cpp → next/new/net.cpp Executable file → Normal file
Просмотреть файл

@ -1,100 +1,100 @@
#include "net.h"
#include "log.h"
#include "message.h"
// TODO(feiga) remove this
#define MULTIVERSO_USE_MPI
namespace multiverso {
#ifdef MULTIVERSO_USE_MPI
#include <mpi.h>
class MPINetWrapper : public NetInterface {
public:
MPINetWrapper() : more_(std::numeric_limits<int>::max()) {}
void Init(int* argc, char** argv) override {
// MPI_Init(argc, &argv);
MPI_Initialized(&inited_);
if (!inited_) {
int flag = 0;
MPI_Init_thread(argc, &argv, MPI_THREAD_MULTIPLE, &flag);
CHECK(flag == MPI_THREAD_MULTIPLE);
}
MPI_Comm_rank(MPI_COMM_WORLD, &rank_);
MPI_Comm_size(MPI_COMM_WORLD, &size_);
Log::Info("%s net util inited, rank = %d, size = %d\n",
name().c_str(), rank(), size());
}
void Finalize() override { MPI_Finalize(); }
int rank() const override { return rank_; }
int size() const override { return size_; }
std::string name() const override { return "MPI"; }
size_t Send(const MessagePtr& msg) override {
size_t size = Message::kHeaderSize;
MPI_Send(msg->header(), Message::kHeaderSize, MPI_BYTE,
msg->dst(), 0, MPI_COMM_WORLD);
// Send multiple msg
for (auto& blob : msg->data()) {
CHECK_NOTNULL(blob.data());
MPI_Send(blob.data(), static_cast<int>(blob.size()), MPI_BYTE, msg->dst(),
0, MPI_COMM_WORLD);
size += blob.size();
}
// Send an extra over tag indicating the finish of this Message
MPI_Send(&more_, sizeof(int), MPI_BYTE, msg->dst(),
0, MPI_COMM_WORLD);
return size + sizeof(int);
}
size_t Recv(MessagePtr* msg_ptr) override {
// Receiving a Message from multiple recv
MessagePtr& msg = *msg_ptr;
MPI_Status status;
MPI_Recv(msg->header(), Message::kHeaderSize,
MPI_BYTE, MPI_ANY_SOURCE,
0, MPI_COMM_WORLD, &status);
size_t size = Message::kHeaderSize;
while (true) {
int count;
MPI_Probe(msg->src(), 0, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_BYTE, &count);
Blob blob(count);
// We only receive from msg->src() until we recv the overtag msg
MPI_Recv(blob.data(), count, MPI_BYTE, msg->src(),
0, MPI_COMM_WORLD, &status);
size += count;
if (count == sizeof(int) && blob.As<int>() == more_) break;
msg->Push(blob);
}
return size;
}
private:
const int more_;
int inited_;
int rank_;
int size_;
};
#endif
NetInterface* NetInterface::Get() {
#ifdef MULTIVERSO_USE_ZMQ
Log::Fatal("Not implemented yet\n");
net_util = new ZMQNetInterface();
#else
#ifdef MULTIVERSO_USE_MPI
static MPINetWrapper net_impl;
#endif
#endif
// FATAL Msg
return &net_impl; // net_util.get();
}
#include "net.h"
#include "log.h"
#include "message.h"
// TODO(feiga) remove this
#define MULTIVERSO_USE_MPI
namespace multiverso {
#ifdef MULTIVERSO_USE_MPI
#include <mpi.h>
class MPINetWrapper : public NetInterface {
public:
MPINetWrapper() : more_(std::numeric_limits<int>::max()) {}
void Init(int* argc, char** argv) override {
// MPI_Init(argc, &argv);
MPI_Initialized(&inited_);
if (!inited_) {
int flag = 0;
MPI_Init_thread(argc, &argv, MPI_THREAD_MULTIPLE, &flag);
CHECK(flag == MPI_THREAD_MULTIPLE);
}
MPI_Comm_rank(MPI_COMM_WORLD, &rank_);
MPI_Comm_size(MPI_COMM_WORLD, &size_);
Log::Info("%s net util inited, rank = %d, size = %d\n",
name().c_str(), rank(), size());
}
void Finalize() override { MPI_Finalize(); }
int rank() const override { return rank_; }
int size() const override { return size_; }
std::string name() const override { return "MPI"; }
size_t Send(const MessagePtr& msg) override {
size_t size = Message::kHeaderSize;
MPI_Send(msg->header(), Message::kHeaderSize, MPI_BYTE,
msg->dst(), 0, MPI_COMM_WORLD);
// Send multiple msg
for (auto& blob : msg->data()) {
CHECK_NOTNULL(blob.data());
MPI_Send(blob.data(), static_cast<int>(blob.size()), MPI_BYTE, msg->dst(),
0, MPI_COMM_WORLD);
size += blob.size();
}
// Send an extra over tag indicating the finish of this Message
MPI_Send(&more_, sizeof(int), MPI_BYTE, msg->dst(),
0, MPI_COMM_WORLD);
return size + sizeof(int);
}
size_t Recv(MessagePtr* msg_ptr) override {
// Receiving a Message from multiple recv
MessagePtr& msg = *msg_ptr;
MPI_Status status;
MPI_Recv(msg->header(), Message::kHeaderSize,
MPI_BYTE, MPI_ANY_SOURCE,
0, MPI_COMM_WORLD, &status);
size_t size = Message::kHeaderSize;
while (true) {
int count;
MPI_Probe(msg->src(), 0, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_BYTE, &count);
Blob blob(count);
// We only receive from msg->src() until we recv the overtag msg
MPI_Recv(blob.data(), count, MPI_BYTE, msg->src(),
0, MPI_COMM_WORLD, &status);
size += count;
if (count == sizeof(int) && blob.As<int>() == more_) break;
msg->Push(blob);
}
return size;
}
private:
const int more_;
int inited_;
int rank_;
int size_;
};
#endif
NetInterface* NetInterface::Get() {
#ifdef MULTIVERSO_USE_ZMQ
Log::Fatal("Not implemented yet\n");
net_util = new ZMQNetInterface();
#else
#ifdef MULTIVERSO_USE_MPI
static MPINetWrapper net_impl;
#endif
#endif
// FATAL Msg
return &net_impl; // net_util.get();
}
}

48
next/IMultiverso/new/net.h → next/new/net.h Executable file → Normal file
Просмотреть файл

@ -1,25 +1,25 @@
#ifndef MULTIVERSO_NET_NET_H_
#define MULTIVERSO_NET_NET_H_
#include <string>
#include "message.h"
namespace multiverso {
// Interface of inter process communication method
class NetInterface {
public:
static NetInterface* Get();
virtual void Init(int* argc = nullptr, char** argv = nullptr) = 0;
virtual void Finalize() = 0;
virtual std::string name() const = 0;
virtual int size() const = 0;
virtual int rank() const = 0;
virtual size_t Send(const MessagePtr& msg) = 0;
virtual size_t Recv(MessagePtr* msg) = 0;
};
}
#ifndef MULTIVERSO_NET_NET_H_
#define MULTIVERSO_NET_NET_H_
#include <string>
#include "message.h"
namespace multiverso {
// Interface of inter process communication method
class NetInterface {
public:
static NetInterface* Get();
virtual void Init(int* argc = nullptr, char** argv = nullptr) = 0;
virtual void Finalize() = 0;
virtual std::string name() const = 0;
virtual int size() const = 0;
virtual int rank() const = 0;
virtual size_t Send(const MessagePtr& msg) = 0;
virtual size_t Recv(MessagePtr* msg) = 0;
};
}
#endif // MULTIVERSO_NET_NET_H_

74
next/IMultiverso/new/server.cpp → next/new/server.cpp Executable file → Normal file
Просмотреть файл

@ -1,38 +1,38 @@
#include "server.h"
#include "actor.h"
#include "table_interface.h"
#include "zoo.h"
namespace multiverso {
Server::Server() : Actor(actor::kServer) {
RegisterTask(MsgType::Request_Get, std::bind(
&Server::ProcessGet, this, std::placeholders::_1));
RegisterTask(MsgType::Request_Add, std::bind(
&Server::ProcessAdd, this, std::placeholders::_1));
}
int Server::RegisterTable(ServerTable* server_table) {
int id = static_cast<int>(store_.size());
store_.push_back(server_table);
return id;
}
void Server::ProcessGet(MessagePtr& msg) {
MessagePtr reply(msg->CreateReplyMessage());
int table_id = msg->table_id();
CHECK(table_id >= 0 && table_id < store_.size());
store_[table_id]->ProcessGet(msg->data(), &reply->data());
DeliverTo(actor::kCommunicator, reply);
}
void Server::ProcessAdd(MessagePtr& msg) {
MessagePtr reply(msg->CreateReplyMessage());
int table_id = msg->table_id();
CHECK(table_id >= 0 && table_id < store_.size());
store_[table_id]->ProcessAdd(msg->data());
DeliverTo(actor::kCommunicator, reply);
}
#include "server.h"
#include "actor.h"
#include "table_interface.h"
#include "zoo.h"
namespace multiverso {
Server::Server() : Actor(actor::kServer) {
RegisterTask(MsgType::Request_Get, std::bind(
&Server::ProcessGet, this, std::placeholders::_1));
RegisterTask(MsgType::Request_Add, std::bind(
&Server::ProcessAdd, this, std::placeholders::_1));
}
int Server::RegisterTable(ServerTable* server_table) {
int id = static_cast<int>(store_.size());
store_.push_back(server_table);
return id;
}
void Server::ProcessGet(MessagePtr& msg) {
MessagePtr reply(msg->CreateReplyMessage());
int table_id = msg->table_id();
CHECK(table_id >= 0 && table_id < store_.size());
store_[table_id]->ProcessGet(msg->data(), &reply->data());
DeliverTo(actor::kCommunicator, reply);
}
void Server::ProcessAdd(MessagePtr& msg) {
MessagePtr reply(msg->CreateReplyMessage());
int table_id = msg->table_id();
CHECK(table_id >= 0 && table_id < store_.size());
store_[table_id]->ProcessAdd(msg->data());
DeliverTo(actor::kCommunicator, reply);
}
}

44
next/IMultiverso/new/server.h → next/new/server.h Executable file → Normal file
Просмотреть файл

@ -1,23 +1,23 @@
#ifndef MULTIVERSO_SERVER_H_
#define MULTIVERSO_SERVER_H_
#include "actor.h"
#include <vector>
namespace multiverso {
class ServerTable;
class Server : public Actor {
public:
Server();
int RegisterTable(ServerTable* table);
private:
void ProcessGet(MessagePtr& msg);
void ProcessAdd(MessagePtr& msg);
// contains the parameter data structure and related handle method
std::vector<ServerTable*> store_;
};
}
#ifndef MULTIVERSO_SERVER_H_
#define MULTIVERSO_SERVER_H_
#include "actor.h"
#include <vector>
namespace multiverso {
class ServerTable;
class Server : public Actor {
public:
Server();
int RegisterTable(ServerTable* table);
private:
void ProcessGet(MessagePtr& msg);
void ProcessAdd(MessagePtr& msg);
// contains the parameter data structure and related handle method
std::vector<ServerTable*> store_;
};
}
#endif // MULTIVERSO_SERVER_H_

80
next/IMultiverso/new/table.cpp → next/new/table.cpp Executable file → Normal file
Просмотреть файл

@ -1,41 +1,41 @@
#include "table_interface.h"
#include "zoo.h"
namespace multiverso {
WorkerTable::WorkerTable() {
table_id_ = Zoo::Get()->RegisterTable(this);
}
int WorkerTable::GetAsync(Blob& keys) {
int id = msg_id_++;
waitings_[id] = new Waiter();
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_type(MsgType::Request_Get);
msg->set_msg_id(id);
msg->set_table_id(table_id_);
msg->Push(keys);
Zoo::Get()->Deliver(actor::kWorker, msg);
return id;
}
int WorkerTable::AddAsync(Blob& keys, Blob& values) {
int id = msg_id_++;
waitings_[id] = new Waiter();
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_type(MsgType::Request_Add);
msg->set_msg_id(id);
msg->set_table_id(table_id_);
msg->Push(keys);
msg->Push(values);
Zoo::Get()->Deliver(actor::kWorker, msg);
return id;
}
ServerTable::ServerTable() {
Zoo::Get()->RegisterTable(this);
}
#include "table_interface.h"
#include "zoo.h"
namespace multiverso {
WorkerTable::WorkerTable() {
table_id_ = Zoo::Get()->RegisterTable(this);
}
int WorkerTable::GetAsync(Blob& keys) {
int id = msg_id_++;
waitings_[id] = new Waiter();
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_type(MsgType::Request_Get);
msg->set_msg_id(id);
msg->set_table_id(table_id_);
msg->Push(keys);
Zoo::Get()->Deliver(actor::kWorker, msg);
return id;
}
int WorkerTable::AddAsync(Blob& keys, Blob& values) {
int id = msg_id_++;
waitings_[id] = new Waiter();
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_type(MsgType::Request_Add);
msg->set_msg_id(id);
msg->set_table_id(table_id_);
msg->Push(keys);
msg->Push(values);
Zoo::Get()->Deliver(actor::kWorker, msg);
return id;
}
ServerTable::ServerTable() {
Zoo::Get()->RegisterTable(this);
}
}

Просмотреть файл

@ -1,85 +1,85 @@
#ifndef MULTIVERSO_TABLE_INTERFACE_H_
#define MULTIVERSO_TABLE_INTERFACE_H_
#include <atomic>
#include <string>
#include <unordered_map>
#include "blob.h"
#include "log.h"
#include "waiter.h"
#include "message.h"
namespace multiverso {
// User implementent this
class WorkerTable {
public:
WorkerTable();
virtual ~WorkerTable() {}
void Get(Blob& keys) { Wait(GetAsync(keys)); }
void Add(Blob& keys, Blob& values) { Wait(AddAsync(keys, values)); }
// NOTE(feiga): currently the async interface still doesn't work
int GetAsync(Blob& keys);
int AddAsync(Blob& keys, Blob& values);
void Wait(int id) {
CHECK(waitings_.find(id) != waitings_.end());
waitings_[id]->Wait();
delete waitings_[id];
waitings_[id] = nullptr;
}
void Notify(int id) { waitings_[id]->Notify(); }
virtual int Partition(const std::vector<Blob>& kv,
std::unordered_map<int, std::vector<Blob> >* out) = 0;
virtual void ProcessReplyGet(std::vector<Blob>&) = 0;
// add user defined data structure
private:
int table_id_;
std::mutex m_;
std::unordered_map<int, Waiter*> waitings_;
std::atomic_int msg_id_;
};
// discribe the server parameter storage data structure and related method
class ServerTable {
public:
ServerTable();
virtual void ProcessAdd(const std::vector<Blob>& data) = 0;
virtual void ProcessGet(const std::vector<Blob>& data,
std::vector<Blob>* result) = 0;
// add user defined server storage data structure
};
// TODO(feiga): provide better table creator method
// Abstract Factory to create server and worker
class TableFactory {
// static TableFactory* GetTableFactory();
virtual WorkerTable* CreateWorker() = 0;
virtual ServerTable* CreateServer() = 0;
static TableFactory* fatory_;
};
namespace table {
}
class TableBuilder {
public:
TableBuilder& SetArribute(const std::string& name, const std::string& val);
WorkerTable* WorkerTableBuild();
ServerTable* ServerTableBuild();
private:
std::unordered_map<std::string, std::string> params_;
};
}
#ifndef MULTIVERSO_TABLE_INTERFACE_H_
#define MULTIVERSO_TABLE_INTERFACE_H_
#include <atomic>
#include <string>
#include <unordered_map>
#include "blob.h"
#include "log.h"
#include "waiter.h"
#include "message.h"
namespace multiverso {
// User implementent this
class WorkerTable {
public:
WorkerTable();
virtual ~WorkerTable() {}
void Get(Blob& keys) { Wait(GetAsync(keys)); }
void Add(Blob& keys, Blob& values) { Wait(AddAsync(keys, values)); }
// NOTE(feiga): currently the async interface still doesn't work
int GetAsync(Blob& keys);
int AddAsync(Blob& keys, Blob& values);
void Wait(int id) {
CHECK(waitings_.find(id) != waitings_.end());
waitings_[id]->Wait();
delete waitings_[id];
waitings_[id] = nullptr;
}
void Notify(int id) { waitings_[id]->Notify(); }
virtual int Partition(const std::vector<Blob>& kv,
std::unordered_map<int, std::vector<Blob> >* out) = 0;
virtual void ProcessReplyGet(std::vector<Blob>&) = 0;
// add user defined data structure
private:
int table_id_;
std::mutex m_;
std::unordered_map<int, Waiter*> waitings_;
std::atomic_int msg_id_;
};
// discribe the server parameter storage data structure and related method
class ServerTable {
public:
ServerTable();
virtual void ProcessAdd(const std::vector<Blob>& data) = 0;
virtual void ProcessGet(const std::vector<Blob>& data,
std::vector<Blob>* result) = 0;
// add user defined server storage data structure
};
// TODO(feiga): provide better table creator method
// Abstract Factory to create server and worker
class TableFactory {
// static TableFactory* GetTableFactory();
virtual WorkerTable* CreateWorker() = 0;
virtual ServerTable* CreateServer() = 0;
static TableFactory* fatory_;
};
namespace table {
}
class TableBuilder {
public:
TableBuilder& SetArribute(const std::string& name, const std::string& val);
WorkerTable* WorkerTableBuild();
ServerTable* ServerTableBuild();
private:
std::unordered_map<std::string, std::string> params_;
};
}
#endif // MULTIVERSO_TABLE_INTERFACE_H_

66
next/IMultiverso/new/waiter.h → next/new/waiter.h Executable file → Normal file
Просмотреть файл

@ -1,34 +1,34 @@
#ifndef MULTIVERSO_WAITER_H_
#define MULTIVERSO_WAITER_H_
#include <mutex>
#include <condition_variable>
namespace multiverso {
class Waiter {
public:
explicit Waiter(int num_wait = 1) : num_wait_(num_wait) {}
void Wait() {
std::unique_lock<std::mutex> lock(mutex_);
while (num_wait_ > 0) cv_.wait(lock);
}
void Notify() {
std::unique_lock<std::mutex> lock(mutex_);
--num_wait_;
cv_.notify_all();
}
void Reset(int num_wait = 1) { num_wait_ = num_wait; }
private:
std::mutex mutex_;
std::condition_variable cv_;
int num_wait_;
};
}
#ifndef MULTIVERSO_WAITER_H_
#define MULTIVERSO_WAITER_H_
#include <mutex>
#include <condition_variable>
namespace multiverso {
class Waiter {
public:
explicit Waiter(int num_wait = 1) : num_wait_(num_wait) {}
void Wait() {
std::unique_lock<std::mutex> lock(mutex_);
while (num_wait_ > 0) cv_.wait(lock);
}
void Notify() {
std::unique_lock<std::mutex> lock(mutex_);
--num_wait_;
cv_.notify_all();
}
void Reset(int num_wait = 1) { num_wait_ = num_wait; }
private:
std::mutex mutex_;
std::condition_variable cv_;
int num_wait_;
};
}
#endif // MULTIVERSO_WAITER_H_

142
next/IMultiverso/new/worker.cpp → next/new/worker.cpp Executable file → Normal file
Просмотреть файл

@ -1,72 +1,72 @@
#include "worker.h"
#include "mt_queue.h"
#include "zoo.h"
namespace multiverso {
Worker::Worker() : Actor(actor::kWorker) {
using namespace std::placeholders;
RegisterTask(MsgType::Request_Get, std::bind(&Worker::ProcessGet, this, _1));
RegisterTask(MsgType::Request_Add, std::bind(&Worker::ProcessAdd, this, _1));
}
int Worker::RegisterTable(WorkerTable* worker_table) {
CHECK_NOTNULL(worker_table);
int id = static_cast<int>(cache_.size());
cache_.push_back(worker_table);
return id;
}
void Worker::ProcessGet(MessagePtr& msg) {
int table_id = msg->table_id();
int msg_id = msg->msg_id();
std::unordered_map<int, std::vector<Blob>> partitioned_key;
int num = cache_[table_id]->Partition(msg->data(), &partitioned_key);
for (auto& it : partitioned_key) {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_dst(it.first);
msg->set_type(MsgType::Request_Get);
msg->set_msg_id(msg_id);
msg->set_table_id(table_id);
msg->set_data(it.second);
DeliverTo(actor::kCommunicator, msg);
}
// TODO(feiga): stop and wait, this is a naive implementation
for (int i = 0; i < num; ++i) {
MessagePtr msg;
CHECK(mailbox_->Pop(msg));
CHECK(msg->type() == MsgType::Reply_Get);
cache_[table_id]->ProcessReplyGet(msg->data());
}
cache_[table_id]->Notify(msg_id);
}
void Worker::ProcessAdd(MessagePtr& msg) {
int table_id = msg->table_id();
int msg_id = msg->msg_id();
std::unordered_map<int, std::vector<Blob>> partitioned_kv;
CHECK_NOTNULL(msg.get());
CHECK(!msg->data().empty());
int num = cache_[table_id]->Partition(msg->data(), &partitioned_kv);
for (auto& it : partitioned_kv) {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_dst(it.first);
msg->set_type(MsgType::Request_Add);
msg->set_msg_id(msg_id);
msg->set_table_id(table_id);
msg->set_data(it.second);
DeliverTo(actor::kCommunicator, msg);
}
for (int i = 0; i < num; ++i) {
MessagePtr msg;
CHECK(mailbox_->Pop(msg));
CHECK(msg->type() == MsgType::Reply_Add);
}
// some cv issue
cache_[table_id]->Notify(msg_id);
}
#include "worker.h"
#include "mt_queue.h"
#include "zoo.h"
namespace multiverso {
Worker::Worker() : Actor(actor::kWorker) {
using namespace std::placeholders;
RegisterTask(MsgType::Request_Get, std::bind(&Worker::ProcessGet, this, _1));
RegisterTask(MsgType::Request_Add, std::bind(&Worker::ProcessAdd, this, _1));
}
int Worker::RegisterTable(WorkerTable* worker_table) {
CHECK_NOTNULL(worker_table);
int id = static_cast<int>(cache_.size());
cache_.push_back(worker_table);
return id;
}
void Worker::ProcessGet(MessagePtr& msg) {
int table_id = msg->table_id();
int msg_id = msg->msg_id();
std::unordered_map<int, std::vector<Blob>> partitioned_key;
int num = cache_[table_id]->Partition(msg->data(), &partitioned_key);
for (auto& it : partitioned_key) {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_dst(it.first);
msg->set_type(MsgType::Request_Get);
msg->set_msg_id(msg_id);
msg->set_table_id(table_id);
msg->set_data(it.second);
DeliverTo(actor::kCommunicator, msg);
}
// TODO(feiga): stop and wait, this is a naive implementation
for (int i = 0; i < num; ++i) {
MessagePtr msg;
CHECK(mailbox_->Pop(msg));
CHECK(msg->type() == MsgType::Reply_Get);
cache_[table_id]->ProcessReplyGet(msg->data());
}
cache_[table_id]->Notify(msg_id);
}
void Worker::ProcessAdd(MessagePtr& msg) {
int table_id = msg->table_id();
int msg_id = msg->msg_id();
std::unordered_map<int, std::vector<Blob>> partitioned_kv;
CHECK_NOTNULL(msg.get());
CHECK(!msg->data().empty());
int num = cache_[table_id]->Partition(msg->data(), &partitioned_kv);
for (auto& it : partitioned_kv) {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(Zoo::Get()->rank());
msg->set_dst(it.first);
msg->set_type(MsgType::Request_Add);
msg->set_msg_id(msg_id);
msg->set_table_id(table_id);
msg->set_data(it.second);
DeliverTo(actor::kCommunicator, msg);
}
for (int i = 0; i < num; ++i) {
MessagePtr msg;
CHECK(mailbox_->Pop(msg));
CHECK(msg->type() == MsgType::Reply_Add);
}
// some cv issue
cache_[table_id]->Notify(msg_id);
}
}

42
next/IMultiverso/new/worker.h → next/new/worker.h Executable file → Normal file
Просмотреть файл

@ -1,22 +1,22 @@
#ifndef MULTIVERSO_WORKER_H_
#define MULTIVERSO_WORKER_H_
#include "actor.h"
namespace multiverso {
class WorkerTable;
class Worker : public Actor {
public:
Worker();
int RegisterTable(WorkerTable* worker_table);
private:
void ProcessGet(MessagePtr& msg);
void ProcessAdd(MessagePtr& msg);
std::vector<WorkerTable*> cache_;
};
}
#ifndef MULTIVERSO_WORKER_H_
#define MULTIVERSO_WORKER_H_
#include "actor.h"
namespace multiverso {
class WorkerTable;
class Worker : public Actor {
public:
Worker();
int RegisterTable(WorkerTable* worker_table);
private:
void ProcessGet(MessagePtr& msg);
void ProcessAdd(MessagePtr& msg);
std::vector<WorkerTable*> cache_;
};
}
#endif // MULTIVERSO_WORKER_H_

180
next/IMultiverso/new/zoo.cpp → next/new/zoo.cpp Executable file → Normal file
Просмотреть файл

@ -1,91 +1,91 @@
#include "communicator.h"
#include "zoo.h"
#include "message.h"
#include "actor.h"
#include "mt_queue.h"
#include "net.h"
#include "log.h"
#include "worker.h"
#include "server.h"
#include "controller.h"
namespace multiverso {
Zoo::Zoo() {}
Zoo::~Zoo() {}
void Zoo::Start() {
net_util_ = NetInterface::Get();
net_util_->Init();
// These actors can either reside in one process, or in different process
// based on the configuration
// For example, we can have a kind of configuration, N machines, each have a
// worker actor(thread), a server actor. Meanwhile, rank 0 node also servers
// as controller.
// We can also have another configuration, N machine, rank 0 acts as
// controller, rank 1...M as workers(M < N), and rank M... N-1 as servers
// All nodes have a communicator, and one(at least one) or more of other three
// kinds of actors
Actor* communicator = new Communicator();
if (rank() == 0) Actor* controler = new Controller();
// if (is_worker)
Actor* worker = new Worker();
// if (is_server)
Actor* server = new Server();
mailbox_.reset(new MtQueue<MessagePtr>);
// Start all actors
for (auto actor : zoo_) { actor.second->Start(); }
// Init the network
// activate the system
Barrier();
Log::Info("Rank %d: Zoo start sucessfully\n", rank());
}
void Zoo::Stop() {
// Stop the system
Barrier();
// Stop all actors
for (auto actor : zoo_) { actor.second->Stop(); }
// Stop the network
net_util_->Finalize();
}
int Zoo::rank() const { return net_util_->rank(); }
int Zoo::size() const { return net_util_->size(); }
void Zoo::Deliver(const std::string& name, MessagePtr& msg) {
CHECK(zoo_.find(name) != zoo_.end());
zoo_[name]->Accept(msg);
}
void Zoo::Accept(MessagePtr& msg) {
mailbox_->Push(msg);
}
void Zoo::Barrier() {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(rank());
msg->set_dst(0); // rank 0 acts as the controller master. TODO(feiga):
// consider a method to encapsulate this node information
msg->set_type(MsgType::Control_Barrier);
Deliver(actor::kCommunicator, msg);
// wait for reply
mailbox_->Pop(msg);
CHECK(msg->type() == MsgType::Control_Reply_Barrier);
}
int Zoo::RegisterTable(WorkerTable* worker_table) {
return dynamic_cast<Worker*>(zoo_[actor::kWorker])
->RegisterTable(worker_table);
}
int Zoo::RegisterTable(ServerTable* server_table) {
return dynamic_cast<Server*>(zoo_[actor::kServer])
->RegisterTable(server_table);
}
#include "communicator.h"
#include "zoo.h"
#include "message.h"
#include "actor.h"
#include "mt_queue.h"
#include "net.h"
#include "log.h"
#include "worker.h"
#include "server.h"
#include "controller.h"
namespace multiverso {
Zoo::Zoo() {}
Zoo::~Zoo() {}
void Zoo::Start() {
net_util_ = NetInterface::Get();
net_util_->Init();
// These actors can either reside in one process, or in different process
// based on the configuration
// For example, we can have a kind of configuration, N machines, each have a
// worker actor(thread), a server actor. Meanwhile, rank 0 node also servers
// as controller.
// We can also have another configuration, N machine, rank 0 acts as
// controller, rank 1...M as workers(M < N), and rank M... N-1 as servers
// All nodes have a communicator, and one(at least one) or more of other three
// kinds of actors
Actor* communicator = new Communicator();
if (rank() == 0) Actor* controler = new Controller();
// if (is_worker)
Actor* worker = new Worker();
// if (is_server)
Actor* server = new Server();
mailbox_.reset(new MtQueue<MessagePtr>);
// Start all actors
for (auto actor : zoo_) { actor.second->Start(); }
// Init the network
// activate the system
Barrier();
Log::Info("Rank %d: Zoo start sucessfully\n", rank());
}
void Zoo::Stop() {
// Stop the system
Barrier();
// Stop all actors
for (auto actor : zoo_) { actor.second->Stop(); }
// Stop the network
net_util_->Finalize();
}
int Zoo::rank() const { return net_util_->rank(); }
int Zoo::size() const { return net_util_->size(); }
void Zoo::Deliver(const std::string& name, MessagePtr& msg) {
CHECK(zoo_.find(name) != zoo_.end());
zoo_[name]->Accept(msg);
}
void Zoo::Accept(MessagePtr& msg) {
mailbox_->Push(msg);
}
void Zoo::Barrier() {
MessagePtr msg = std::make_unique<Message>();
msg->set_src(rank());
msg->set_dst(0); // rank 0 acts as the controller master. TODO(feiga):
// consider a method to encapsulate this node information
msg->set_type(MsgType::Control_Barrier);
Deliver(actor::kCommunicator, msg);
// wait for reply
mailbox_->Pop(msg);
CHECK(msg->type() == MsgType::Control_Reply_Barrier);
}
int Zoo::RegisterTable(WorkerTable* worker_table) {
return dynamic_cast<Worker*>(zoo_[actor::kWorker])
->RegisterTable(worker_table);
}
int Zoo::RegisterTable(ServerTable* server_table) {
return dynamic_cast<Server*>(zoo_[actor::kServer])
->RegisterTable(server_table);
}
}

128
next/IMultiverso/new/zoo.h → next/new/zoo.h Executable file → Normal file
Просмотреть файл

@ -1,65 +1,65 @@
#ifndef MULTIVERSO_ZOO_H_
#define MULTIVERSO_ZOO_H_
#include <atomic>
#include <string>
#include <unordered_map>
#include "actor.h"
#include "table_interface.h"
namespace multiverso {
class NetInterface;
// The dashboard
// 1. Manage all components in the system, include all actors, and network env
// 2. Maintain system information, provide method to access this information
// 3. Control the system, to start and end
class Zoo {
public:
~Zoo();
static Zoo* Get() { static Zoo zoo; return &zoo; };
// Start all actors
void Start();
// Stop all actors
void Stop();
void Barrier();
void Deliver(const std::string& name, MessagePtr&);
void Accept(MessagePtr& msg);
int rank() const;
int size() const;
// TODO(to change)
int num_workers() const { return size(); }
int num_servers() const { return size(); }
int RegisterTable(WorkerTable* worker_table);
int RegisterTable(ServerTable* server_table);
private:
// private constructor
Zoo();
void Register(const std::string name, Actor* actor) {
CHECK(zoo_[name] == nullptr);
zoo_[name] = actor;
}
friend class Actor;
std::unordered_map<std::string, Actor*> zoo_;
std::unique_ptr<MtQueue<MessagePtr>> mailbox_;
std::atomic_int id_;
NetInterface* net_util_;
};
}
#ifndef MULTIVERSO_ZOO_H_
#define MULTIVERSO_ZOO_H_
#include <atomic>
#include <string>
#include <unordered_map>
#include "actor.h"
#include "table_interface.h"
namespace multiverso {
class NetInterface;
// The dashboard
// 1. Manage all components in the system, include all actors, and network env
// 2. Maintain system information, provide method to access this information
// 3. Control the system, to start and end
class Zoo {
public:
~Zoo();
static Zoo* Get() { static Zoo zoo; return &zoo; };
// Start all actors
void Start();
// Stop all actors
void Stop();
void Barrier();
void Deliver(const std::string& name, MessagePtr&);
void Accept(MessagePtr& msg);
int rank() const;
int size() const;
// TODO(to change)
int num_workers() const { return size(); }
int num_servers() const { return size(); }
int RegisterTable(WorkerTable* worker_table);
int RegisterTable(ServerTable* server_table);
private:
// private constructor
Zoo();
void Register(const std::string name, Actor* actor) {
CHECK(zoo_[name] == nullptr);
zoo_[name] = actor;
}
friend class Actor;
std::unordered_map<std::string, Actor*> zoo_;
std::unique_ptr<MtQueue<MessagePtr>> mailbox_;
std::atomic_int id_;
NetInterface* net_util_;
};
}
#endif // MULTIVERSO_ZOO_H_

Просмотреть файл

@ -1,3 +0,0 @@
ADD_SUBDIRECTORY(multiverso)
ADD_SUBDIRECTORY(multiverso_server)

Просмотреть файл

@ -1,16 +0,0 @@
INCLUDE_DIRECTORIES(${HEADERS_DIR})
INCLUDE_DIRECTORIES(${THIRD_PARTY_INC})
MESSAGE(STATUS "multiver ${THIRD_PARTY_INC}")
SET(MULTIVERSO_SRC multiverso.cpp aggregator.cpp endpoint_list.cpp stop_watch.cpp zmq_util.cpp barrier.cpp lock.cpp parameter_loader.cpp table.cpp communicator.cpp log.cpp row.cpp table_iter.cpp data_block.cpp mpi_util.cpp row_iter.cpp trainer.cpp delta_pool.cpp msg_pack.cpp server.cpp vector_clock.cpp io.cpp hdfs_file_sys.cpp local_file_sys.cpp
)
LINK_DIRECTORIES(${THIRD_PARTY_LIB})
LINK_DIRECTORIES(${JVM_LIB})
ADD_LIBRARY(multiverso ${MULTIVERSO_SRC})
TARGET_LINK_LIBRARIES(multiverso jvm hdfs mpich mpl zmq pthread)
SET_PROPERTY(TARGET multiverso PROPERTY CXX_STANDARD 11)

Просмотреть файл

@ -1,339 +0,0 @@
#include "aggregator.h"
#include "barrier.h"
#include "delta_pool.h"
#include "meta.h"
#include "msg_pack.h"
#include "multiverso.h"
#include "table.h"
#include "table_iter.h"
#include "row.h"
#include "row_iter.h"
#include "vector_clock.h"
#include "zmq_util.h"
#include "lock.h"
#include "zmq.hpp"
#include <unordered_map>
namespace multiverso
{
void IAggregator::CreateTable(integer_t table_id, integer_t rows,
integer_t cols, Type type, Format default_format,
int64_t memory_pool_size)
{
if (table_id >= tables_.size())
{
tables_.resize(table_id + 1);
}
tables_[table_id] = new Table(table_id,
rows, cols, type, default_format, memory_pool_size);
}
int IAggregator::SetAggregatorRow(integer_t table_id, integer_t row_id,
Format format, integer_t capacity)
{
return tables_[table_id]->SetRow(row_id, format, capacity);
}
/*!
* \brief All operation is finished by caller
*/
class SimpleAggregator : public IAggregator
{
public:
SimpleAggregator() : lock_pool_(kLockNum) {
socket_ = ZMQUtil::CreateSocket();
}
~SimpleAggregator() { delete socket_; }
void Add(int trainer, integer_t table,
integer_t row, integer_t col, void* delta) override
{
lock_pool_.Lock(table + row);
tables_[table]->GetRow(row)->Add(delta);
lock_pool_.Unlock(table + row);
}
void BatchAdd(int trainer, integer_t table,
integer_t row, void* row_data) override
{
lock_pool_.Lock(table + row);
tables_[table]->GetRow(row)->BatchAdd(row_data);
lock_pool_.Unlock(table + row);
}
void Flush(int trainer) override
{
Send(0, socket_);
}
void Clock(int trainer) override
{
MsgPack* msg = new MsgPack(MsgType::Clock, MsgArrow::Worker2Server,
Multiverso::ProcessRank(), 0);
msg->Send(socket_); // Send the clock message
delete msg;
MsgPack reply(socket_); // Wait for reply
}
private:
const int kLockNum = 41;
LockManager lock_pool_;
zmq::socket_t* socket_;
};
/*!
* \brief All operation is finished by the background thread, worker just
* push updates
*/
class AsyncAggregator : public IAggregator
{
public:
/*!
* \brief Construct an aggregator.
* \param num_threads number of background aggregator threads
* \param num_trainers number of trainer thread
*/
AsyncAggregator(int num_threads, int num_trainers);
~AsyncAggregator();
void Add(int trainer, integer_t table,
integer_t row, integer_t col, void* delta) override;
void BatchAdd(int trainer, integer_t table,
integer_t row, void* row_delta) override
{
Log::Fatal("Not implement: "
"async aggregator can only holds sparse update\n");
}
void Flush(int trainer) override
{
Add(trainer, 0, static_cast<integer_t>(DeltaType::Flush), 0, nullptr);
}
void Clock(int trainer) override
{
Add(trainer, 0, static_cast<integer_t>(DeltaType::Clock), 0, nullptr);
}
/*! \brief Wait until all client finish sync up */
void Wait() override;
private:
/*! \brief Entrance function of aggregator threads */
void StartThread();
/*! \brief Clock to server */
void Clock(zmq::socket_t* socket);
private:
bool done_; // whether aggregators is done
int num_threads_; // number of aggregator threads
int num_trainers_; // number of trainers
std::vector<DeltaPool*> delta_pools_;
std::vector<std::thread> threads_;
std::atomic<int> thread_counter_;
/*! \brief synchronization barrier used by multiple aggregator */
Barrier* barrier_;
std::mutex mutex_;
std::condition_variable sync_cv_;
bool sync_;
// No copying allowed
AsyncAggregator(const AsyncAggregator&);
void operator=(const AsyncAggregator&);
};
AsyncAggregator::AsyncAggregator(int num_threads, int num_trainers)
: done_(false), num_threads_(num_threads),
num_trainers_(num_trainers), thread_counter_(0)
{
barrier_ = new Barrier(num_threads_);
for (int i = 0; i < num_threads; ++i)
{
delta_pools_.push_back(new DeltaPool(
num_trainers_, kDeltaPoolCapacity));
threads_.push_back(std::thread(&AsyncAggregator::StartThread, this));
}
}
AsyncAggregator::~AsyncAggregator()
{
done_ = true;
for (int i = 0; i < num_threads_; ++i)
{
delta_pools_[i]->Exit();
threads_[i].join();
delete delta_pools_[i];
}
for (auto& table : tables_)
{
delete table;
}
delete barrier_;
}
void AsyncAggregator::Add(int trainer,
integer_t table, integer_t row, integer_t col, void* delta)
{
if (row >= 0)
{
int i = row % num_threads_;
delta_pools_[i]->Push(trainer,
table, row, col, delta, tables_[table]->ElementSize());
}
else
{
for (auto& delta_pool : delta_pools_)
{
// used col to record the trainer id
delta_pool->Push(trainer, table, row, trainer, nullptr, 0);
}
}
}
void AsyncAggregator::StartThread()
{
int id = thread_counter_++;
VectorClock flush_vector(num_trainers_);
VectorClock clock_vector(num_trainers_);
DeltaPool* delta_pool = delta_pools_[id];
barrier_->Wait();
integer_t table, row, col;
void* delta;
zmq::socket_t* socket = ZMQUtil::CreateSocket();
while (delta_pool->Pop(table, row, col, delta))
{
switch (static_cast<DeltaType>(row))
{
case DeltaType::Flush:
if (flush_vector.Update(col))
{
Send(id, socket, num_threads_);
if (barrier_->Wait())
{
for (auto& table : tables_)
{
table->Clear();
}
}
barrier_->Wait();
}
break;
case DeltaType::Clock:
if (clock_vector.Update(col))
{
if (barrier_->Wait())
{
Clock(socket);
}
barrier_->Wait();
}
break;
default: // the general delta type, add update to aggregator table
assert(row >= 0);
tables_[table]->GetRow(row)->Add(col, delta);
}
}
delete socket;
}
void IAggregator::Send(int id, zmq::socket_t* socket, int num_threads)
{
int src_rank = Multiverso::ProcessRank();
int num_server = Multiverso::TotalServerCount();
std::vector<MsgPack*> send_list(num_server, nullptr);
std::vector<int> send_ret_size(num_server, 0);
for (int table_id = 0; table_id < tables_.size(); ++table_id)
{
Table* table = tables_[table_id];
TableIterator iter(*table);
for (; iter.HasNext(); iter.Next())
{
integer_t row_id = iter.RowId();
if (row_id % num_threads != id)
{
continue;
}
RowBase* row = iter.Row();
int dst_rank = (table_id + row_id) % num_server;
if (send_list[dst_rank] == nullptr)
{
send_list[dst_rank] = new MsgPack(MsgType::Add,
MsgArrow::Worker2Server, src_rank, dst_rank);
send_ret_size[dst_rank] = 0;
}
// Format: table_id, row_id, number
// col_1, col2, ..., col_n, val_1, val_2, ..., val_n;
int msg_size = sizeof(integer_t)* 3 + row->NonzeroSize() *
(table->ElementSize() + sizeof(integer_t));
if (msg_size > kMaxMsgSize)
{
// TODO(feiga): we currently assume the row serialized size
// not ecceed kMaxMsgSize. should solve the issue later.
Log::Error("Row size exceed the max size of message\n");
}
if (send_ret_size[dst_rank] + msg_size > kMaxMsgSize)
{
send_list[dst_rank]->Send(socket);
delete send_list[dst_rank];
send_list[dst_rank] = new MsgPack(MsgType::Add,
MsgArrow::Worker2Server, src_rank, dst_rank);
send_ret_size[dst_rank] = 0;
}
zmq::message_t* msg = new zmq::message_t(msg_size);
integer_t* buffer = static_cast<integer_t*>(msg->data());
buffer[0] = table_id;
buffer[1] = row_id;
row->Serialize(buffer + 2);
send_list[dst_rank]->Push(msg);
send_ret_size[dst_rank] += msg_size;
}
}
for (int i = 0; i < num_server; ++i)
{
if (send_ret_size[i] > 0)
{
send_list[i]->Send(socket);
delete send_list[i];
}
}
}
void AsyncAggregator::Clock(zmq::socket_t* socket)
{
MsgPack* msg = new MsgPack(MsgType::Clock, MsgArrow::Worker2Server,
Multiverso::ProcessRank(), 0);
msg->Send(socket); // Send the clock message
delete msg;
MsgPack reply(socket); // Wait for reply
// signal conditions variable to awake trainer process
std::unique_lock<std::mutex> lock(mutex_);
sync_cv_.notify_all();
}
void AsyncAggregator::Wait()
{
std::unique_lock<std::mutex> lock(mutex_);
sync_cv_.wait(lock);
}
// Factory method
IAggregator* IAggregator::CreateAggregator(int num_aggregators, int num_trainers)
{
// TODO(feiga): temporaly only async
// TODO, add simple aggregator createor
return new AsyncAggregator(num_aggregators, num_trainers);
}
}

Просмотреть файл

@ -1,45 +0,0 @@
#include "log.h"
#include "barrier.h"
namespace multiverso
{
Barrier::Barrier(int num_threads)
{
num_in_waiting_ = 0;
barrier_size_ = 0;
ResetNumThreads(num_threads);
}
// TODO and DISCUSSION: If the barrier object is in a waiting status,
// changing the barrier size may cause confusion. This method should be
// called in the empty status.
int Barrier::ResetNumThreads(int num_threads)
{
if (num_threads > 0)
{
barrier_size_ = num_threads;
return 0;
}
else
{
Log::Error("Invalid barrier size %d, reset ignored.\n", num_threads);
return -1;
}
}
bool Barrier::Wait()
{
std::unique_lock<std::mutex> lock(mutex_);
if ((++num_in_waiting_) == barrier_size_) // the last one comes
{
num_in_waiting_ = 0;
cond_.notify_all();
return true;
}
else
{
cond_.wait(lock);
return false;
}
}
}

Просмотреть файл

@ -1,247 +0,0 @@
#include "meta.h"
#include "log.h"
#include "server.h"
#include "zmq_util.h"
#include "mpi_util.h"
#include "msg_pack.h"
#include "endpoint_list.h"
#include "communicator.h"
namespace multiverso
{
// Creates Communicator object and starts communication thread.
Communicator::Communicator(const Config &config, int *argc, char **argv[])
{
reg_info_.proc_rank = -1;
reg_info_.proc_count = -1;
reg_info_.server_count = -1;
server_ = nullptr;
#if defined (_MPI_VERSION_)
// starts MPI first
MPIUtil::Init(argc, argv);
reg_info_.proc_rank = MPIUtil::MPIRank();
reg_info_.proc_count = MPIUtil::MPISize();
mpi_finalize_ = true;
// Starts an affiliated server
reg_info_.server_count = config.num_servers;
if (reg_info_.server_count >= 0
|| reg_info_.server_count >= reg_info_.proc_count)
{
reg_info_.server_count = reg_info_.proc_count;
}
if (reg_info_.proc_rank < reg_info_.server_count)
{
server_ = new Server(reg_info_.proc_rank, reg_info_.proc_count,
kSERVER_ENDPOINT.c_str());
}
#endif
// starts communication thread
is_working_ = false;
comm_thread_ = std::thread([=](){
StartThread(config.server_endpoint_file);
});
// keeps waiting until the communicator thread goes into the working routine
while (!is_working_)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
// Destroies the Communicator object.
Communicator::~Communicator()
{
delete server_;
// POTENTIAL ISSUE: if stoping the communicator too early, there might
// be unprocessed messages. We should design a method
// to make sure that all messages have been sent.
std::this_thread::sleep_for(std::chrono::seconds(1));
is_working_ = false;
comm_thread_.join();
#if defined (_MPI_VERSION_)
if (mpi_finalize_)
{
MPIUtil::Close();
}
#endif
}
RegisterInfo Communicator::Register(zmq::socket_t *socket,
const Config &config, int num_trainers)
{
if (reg_info_.server_count < 0)
{
reg_info_.server_count = static_cast<int>(dealers_.size());
}
// send a register message to server 0
// message format: num_local_trainers:int, num_servers:int, max_delay:int
MsgPack msg_pack(MsgType::Register, MsgArrow::Worker2Server,
reg_info_.proc_rank, 0);
zmq::message_t *msg = new zmq::message_t(3 * sizeof(int));
int *buffer = static_cast<int*>(msg->data());
buffer[0] = static_cast<int>(num_trainers); // number of local trainers
buffer[1] = reg_info_.server_count; // local server count configuration
buffer[2] = config.max_delay; // delay bound (max staleness)
msg_pack.Push(msg);
msg_pack.Send(socket);
// get the reply
MsgPack reply(socket);
buffer = static_cast<int*>(reply.GetMsg(1)->data());
if (reg_info_.proc_rank < 0)
{
reg_info_.proc_rank = buffer[0];
}
if (reg_info_.proc_count < 0)
{
reg_info_.proc_count = buffer[1];
}
if (reg_info_.server_count != buffer[2])
{
Log::Fatal(
"Rank %d/%d: Inconsistance in number of servers: local=%d vs. global=%d\n",
reg_info_.proc_rank, reg_info_.proc_count,
reg_info_.server_count, buffer[2]);
}
reg_info_.total_trainer_count = buffer[3];
return reg_info_;
}
//int Communicator::MPIRank() { return MPIUtil::MPIRank(); }
//int Communicator::MPISize() { return MPIUtil::MPISize(); }
zmq::socket_t *Communicator::CreateSocket()
{
return ZMQUtil::CreateSocket();
}
// Initialization when starting the communication thread.
void Communicator::Init(std::string server_endpoint_file)
{
router_ = new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_ROUTER);
router_->bind(kCOMM_ENDPOINT.c_str());
#if defined (_MPI_VERSION_)
dealers_.push_back(
new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_DEALER));
dealers_[0]->connect(kSERVER_ENDPOINT.c_str());
#else
EndpointList endpoint_list(server_endpoint_file);
for (int server_id = 0; server_id < endpoint_list.Size(); ++server_id)
{
dealers_.push_back(
new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_DEALER));
dealers_[server_id]->connect(
("tcp://" + endpoint_list.GetEndpoint(server_id)).c_str());
}
#endif
poll_count_ = static_cast<int>(dealers_.size() + 1);
poll_items_ = new zmq::pollitem_t[poll_count_];
poll_items_[0] = { static_cast<void*>(*router_), 0, ZMQ_POLLIN, 0 };
// poll_items_[0].socket = static_cast<void*>(*router_);
for (int server_id = 0; server_id < dealers_.size(); ++server_id)
{
poll_items_[server_id + 1] = { static_cast<void*>(*dealers_[server_id]), 0, ZMQ_POLLIN, 0 };
}
}
// Cleaning up when closing the communication thread.
void Communicator::Clear()
{
delete router_;
for (auto &item : dealers_)
{
delete item;
}
delete []poll_items_;
}
// Starts the communication thread.
void Communicator::StartThread(std::string server_endpoint_file)
{
Init(server_endpoint_file);
// prepare the polling stuffs
std::vector<zmq::socket_t*> sockets;
sockets.push_back(router_);
for (auto &item : dealers_)
{
sockets.push_back(item);
}
std::queue<std::shared_ptr<MsgPack>> msg_queue;
std::shared_ptr<MsgPack> msg_pack = nullptr;
MsgType type;
MsgArrow arrow;
int src, dst;
// starts working
is_working_ = true;
#if defined (_MPI_VERSION_)
while (is_working_ || MPIUtil::SendQueueSize() > 0)
{
// Probe zmq. If there are too many messages in MPI send queue,
// postpone processing the coming messages
if (MPIUtil::SendQueueSize() < 128)
{
ZMQUtil::ZMQPoll(poll_items_, poll_count_, sockets, msg_queue);
}
// probe mpi
msg_pack = MPIUtil::ProbeAndRecv();
if (msg_pack.get() != nullptr)
{
msg_queue.push(msg_pack);
}
// process the messages in the queue
while (!msg_queue.empty())
{
msg_pack = msg_queue.front();
msg_queue.pop();
msg_pack->GetHeaderInfo(&type, &arrow, &src, &dst);
// If the destination is not the current process, send the
// message to external process with MPI. Or send the message to
// internal threads according to the message arrow.
if (dst != reg_info_.proc_rank)
{
MPIUtil::Send(msg_pack);
}
else if (arrow == MsgArrow::Worker2Server)
{
msg_pack->Send(dealers_[0]);
}
else // server -> worker
{
msg_pack->Send(router_);
}
}
// let MPI send the message in send queue
MPIUtil::Send(nullptr);
}
#else
while (is_working_)
{
ZMQUtil::ZMQPoll(poll_items_, poll_count_, sockets, msg_queue);
while (!msg_queue.empty())
{
msg_pack = msg_queue.front();
msg_queue.pop();
msg_pack->GetHeaderInfo(&type, &arrow, &src, &dst);
if (arrow == MsgArrow::Worker2Server)
{
msg_pack->Send(dealers_[dst]);
}
else // server -> worker
{
msg_pack->Send(router_);
}
}
}
#endif
Clear();
}
}

Просмотреть файл

@ -1,16 +0,0 @@
#include "data_block.h"
namespace multiverso
{
DataBlockBase::DataBlockBase()
{
type_ = DataBlockType::Train;
count_ = 0;
}
DataBlockBase::DataBlockBase(DataBlockType type)
{
type_ = type;
count_ = 0;
}
}

Просмотреть файл

@ -1,177 +0,0 @@
#include "delta_pool.h"
#include <cstring>
namespace multiverso
{
/*!
* \brief A delta entity, represented as a four tuple
*/
struct DeltaPool::Entity
{
integer_t table;
integer_t row;
integer_t col;
int delta[2];
};
/*!
* \brief Entity array is a FIFO queue implemented by a fix-sized array
* This is used as a unit to push and pool in DeltaPool, to
* reduce the multithreads sync frequency.
*/
class DeltaPool::EntityArray
{
public:
EntityArray();
~EntityArray();
/*!
* \brief Push an entity in to queue
* \return true if sucessfully, false if queue is full already
*/
bool Push(integer_t table,
integer_t row, integer_t col, void* value, int size);
/*!
* \brief Pop an entity from queue
* \return true if sucessfully, false if queue is empty
*/
bool Pop(integer_t& table,
integer_t& row, integer_t& col, void*& value);
/*!
* \brief Clear the array
*/
void Clear();
private:
/*! head is the position to pop */
int head_;
/*! tail is the position to push */
int tail_;
/*! underlying array */
Entity* array_;
};
// -- EntityArray implementation area ---------------------------------- //
DeltaPool::EntityArray::EntityArray()
: head_(0), tail_(0)
{
array_ = new Entity[kDeltaArraySize];
}
DeltaPool::EntityArray::~EntityArray()
{
delete[] array_;
}
bool DeltaPool::EntityArray::Push(integer_t table,
integer_t row, integer_t col, void* value, int size)
{
if (tail_ >= kDeltaArraySize)
{
return false;
}
array_[tail_].table = table;
array_[tail_].row = row;
array_[tail_].col = col;
if (value != nullptr)
{
memcpy(array_[tail_].delta, value, size);
}
++tail_;
return true;
}
bool DeltaPool::EntityArray::Pop(integer_t& table,
integer_t& row, integer_t& col, void*& value)
{
if (head_ >= tail_)
{
return false;
}
table = array_[head_].table;
row = array_[head_].row;
col = array_[head_].col;
value = reinterpret_cast<void*>(&(array_[head_].delta));
++head_;
return true;
}
void DeltaPool::EntityArray::Clear()
{
head_ = 0;
tail_ = 0;
}
// -- End of EntityArray implementation area --------------------------- //
// -- DeltaPool implementation area ------------------------------------ //
DeltaPool::DeltaPool(int num_producer, int capacity)
: producer_set_(num_producer)
{
for (int i = 0; i < capacity; ++i)
{
Pointer delta_array(new EntityArray);
empty_queue_.Push(delta_array);
}
}
DeltaPool::~DeltaPool() {}
void DeltaPool::Push(int trainer, integer_t table,
integer_t row, integer_t col, void* delta, int size)
{
Pointer& delta_array = producer_set_[trainer];
if (!delta_array.get())
{
if (!empty_queue_.Pop(delta_array))
{
return;
}
}
while (!delta_array->Push(table, row, col, delta, size))
{
full_queue_.Push(delta_array);
if (!empty_queue_.Pop(delta_array))
{
return;
}
}
if (NeedFlush(row))
{
full_queue_.Push(delta_array);
}
}
bool DeltaPool::Pop(integer_t& table,
integer_t& row, integer_t& col, void*& delta)
{
if (!consumer_.get())
{
if (!full_queue_.Pop(consumer_))
{
return false;
}
}
while (!consumer_->Pop(table, row, col, delta))
{
consumer_->Clear();
empty_queue_.Push(consumer_);
if (!full_queue_.Pop(consumer_))
{
return false;
}
}
return true;
}
void DeltaPool::Exit()
{
full_queue_.Exit();
empty_queue_.Exit();
}
bool DeltaPool::NeedFlush(int row)
{
return static_cast<DeltaType>(row) == DeltaType::Flush ||
static_cast<DeltaType>(row) == DeltaType::Clock;
}
// -- End of DeltaPool implementation area ----------------------------- //
}

Просмотреть файл

@ -1,41 +0,0 @@
#include <fstream>
#include "log.h"
#include "endpoint_list.h"
namespace multiverso
{
EndpointList::EndpointList(std::string filename)
{
int id;
char str[64];
std::vector<int> ids;
std::vector<std::string> endpoints;
FILE *file = fopen(filename.c_str(), "r");
if (file == nullptr)
{
Log::Error("Error on creating EndpointList, FILE OPENING FAIL: %s\n",
filename.c_str());
return;
}
while (fscanf(file, "%d %s", &id, &str) > 0)
{
ids.push_back(id);
endpoints.push_back(str);
}
fclose(file);
endpoints_.resize(ids.size());
for (int i = 0; i < ids.size(); ++i)
{
endpoints_[i] = endpoints[i];
}
}
EndpointList::~EndpointList() {}
std::string EndpointList::GetEndpoint(int id)
{
return (0 <= id && id < endpoints_.size()) ? endpoints_[id] : "";
}
}

Просмотреть файл

@ -1,297 +0,0 @@
#include "hdfs_file_sys.h"
namespace multiverso
{
HDFSStream::HDFSStream(hdfsFS fs, hdfsFile fp, std::string path)
{
fs_ = fs;
fp_ = fp;
path_ = path;
}
HDFSStream::~HDFSStream(void)
{
Flush();
if (hdfsCloseFile(fs_, fp_) != -1)
{
int errsv = errno;
Log::Error("Failed to close HDFSStream %s\n", strerror(errsv));
}
}
/*!
* \brief write data to a file
* \param buf pointer to a memory buffer
* \param size data size
*/
void HDFSStream::Write(const void *buf, size_t size)
{
const char *c_buf = reinterpret_cast<const char*>(buf);
while (size != 0)
{
tSize nwrite = hdfsWrite(fs_, fp_, c_buf, size);
if (nwrite == -1)
{
int errsv = errno;
Log::Fatal("Failed to Write data to HDFSStream %s\n", strerror(errsv));
}
size_t sz = static_cast<size_t>(nwrite);
c_buf += sz;
size -= sz;
}
}
/*!
* \brief read data from Stream
* \param buf pointer to a memory buffer
* \param size the size of buf
*/
size_t HDFSStream::Read(void *buf, size_t size)
{
char *c_buf = static_cast<char*>(buf);
size_t i = 0;
while (i < size)
{
size_t nmax = static_cast<size_t>(std::numeric_limits<tSize>::max());
tSize ret = hdfsRead(fs_, fp_, c_buf + i, std::min(size - i, nmax));
if (ret > 0)
{
size_t n = static_cast<size_t>(ret);
i += n;
}
else if (ret == 0)
{
break;
}
else
{
int errsv = errno;
if (errno == EINTR) continue;
Log::Fatal("Failed to Read HDFSStream %s\n", strerror(errsv));
}
}
return i;
}
/*!
* \brief move the position point to seekOrigin + offset
* \param offset the offset(bytes number) to change the position point
* \param seekOrigin the reference position
*/
void HDFSStream::Seek(size_t offset, SeekOrigin seekOrigin)
{
tOffset pos;
if (seekOrigin == SeekOrigin::kBegin)
{
pos = static_cast<tOffset>(offset);
}
else if (seekOrigin == SeekOrigin::kCurrent)
{
pos = hdfsTell(fs_, fp_);
if (pos == -1)
{
int errsv = errno;
Log::Fatal("Failed to get Current position of HDFSStream: %s\n", strerror(errsv));
}
pos += static_cast<tOffset>(offset);
}
else
{
hdfsFileInfo *info = hdfsGetPathInfo(fs_, path_.c_str());
if (info == nullptr)
{
int errsv = errno;
Log::Fatal("Failed to get Current position of HDFSStream: %s\n", strerror(errsv));
}
pos = info->mSize + static_cast<tOffset>(offset);
hdfsFreeFileInfo(info, 1);
}
if (hdfsSeek(fs_, fp_, pos) != 0)
{
int errsv = errno;
Log::Error("Failed to Seek HDFSStream: %s\n", strerror(errsv));
}
}
/*!
* \brief flush local buffer
*/
void HDFSStream::Flush()
{
if (hdfsHSync(fs_, fp_) == -1)
{
int errsv = errno;
Log::Error("Failed to Flush HDFSStream: %s\n", strerror(errsv));
}
}
HDFSFileSystem::HDFSFileSystem(const std::string host)
{
if (host.length() == 0)
namenode_ = "default";
else
namenode_ = host;
fs_ = hdfsConnect(namenode_.c_str(), 0);
if (fs_ == NULL)
Log::Fatal("Failed connect HDFS namenode '%s'\n", namenode_.c_str());
}
HDFSFileSystem::~HDFSFileSystem(void)
{
}
void HDFSFileSystem::Close(void)
{
if (fs_ != nullptr && hdfsDisconnect(fs_) != 0)
{
int errsv = errno;
Log::Fatal("HDFSStream.hdfsDisconnect Error: %s\n", strerror(errsv));
}
}
/*!
* \brief create a Stream
* \param path the path of the file
* \param mode "w" - create an empty file to store data;
* "a" - open the file to append data to it
* "r" - open the file to read
* \return the Stream which is used to write or read data
*/
Stream *HDFSFileSystem::Open(const std::string path,
const char *mode)
{
using namespace std;
int flag = 0;
if (!strcmp(mode, "r"))
flag = O_RDONLY;
else if (!strcmp(mode, "w"))
flag = O_WRONLY;
else if (!strcmp(mode, "a"))
flag = O_WRONLY | O_APPEND;
else
Log::Fatal("HDFSStream: unknown flag %s\n", mode);
hdfsFile fp = hdfsOpenFile(fs_, path.c_str(), flag,
0, 0, 0);
if (fp != nullptr)
{
return new HDFSStream(fs_, fp, path);
}
else
{
int errsv = errno;
Log::Error("Failed to open HDFSStream %s, %s\n", path.c_str(), strerror(errsv));
return nullptr;
}
}
void HDFSFileSystem::CreateDirectory(const std::string path)
{
if (hdfsCreateDirectory(fs_, path.c_str()) != 0)
{
int errsv = errno;
Log::Error("Failed to CreateDirectory %s, %s\n", path.c_str(), strerror(errsv));
}
}
/*!
* \brief check if the path exists
* \param path the file or directory
*/
bool HDFSFileSystem::Exists(const std::string path)
{
return hdfsExists(fs_, path.c_str()) != -1;
}
/*!
* \brief delete the file or directory
* \param path the file or directory
*/
void HDFSFileSystem::Delete(const std::string path)
{
if (hdfsDelete(fs_, path.c_str(), 1) != 0)
{
int errsv = errno;
Log::Error("Failed to delete %s, %s\n", path.c_str(), strerror(errsv));
}
}
FileInfo *ConvertFileInfo(const std::string &path, const hdfsFileInfo &info)
{
FileInfo *ret = new FileInfo();
ret->path = path;
ret->size = info.mSize;
switch (info.mKind)
{
case 'D': ret->type = FileType::kDirectory; break;
case 'F': ret->type = FileType::kFile; break;
default: Log::Fatal("unknown hdfs file type %c\n", info.mKind);
}
return ret;
}
FileInfo* HDFSFileSystem::GetPathInfo(const std::string path)
{
hdfsFileInfo *info = hdfsGetPathInfo(fs_, path.c_str());
if (info == nullptr)
{
Log::Error("%s does not exist\n", path.c_str());
return nullptr;
}
FileInfo *ret = ConvertFileInfo(path, *info);
hdfsFreeFileInfo(info, 1);
return ret;
}
void HDFSFileSystem::Rename(const std::string old_path,
const std::string new_path)
{
if (hdfsRename(fs_, old_path.c_str(), new_path.c_str()) != 0)
{
int errsv = errno;
Log::Error("Failed to rename %s to %s, %s\n",
old_path.c_str(), new_path.c_str(), strerror(errsv));
}
}
void HDFSFileSystem::Copy(const std::string src, const std::string dst)
{
if (hdfsCopy(fs_, src.c_str(), fs_, dst.c_str()) != 0)
{
int errsv = errno;
Log::Error("Failed to copy %s to %s, %s\n",
src.c_str(), dst.c_str(), strerror(errsv));
}
}
void HDFSFileSystem::ListDirectory(const std::string path,
std::vector<FileInfo*> &out_list)
{
int nentry;
hdfsFileInfo *files = hdfsListDirectory(fs_, path.c_str(), &nentry);
if (files == nullptr)
{
Log::Error("Failed to ListDirectory %s\n", path.c_str());
return;
}
out_list.clear();
for (int i = 0; i < nentry; ++i)
{
std::string tmp(files[i].mName);
size_t pos = tmp.find('/', 7);
Log::Debug("ListDirectory file_name=%s, %d\n", tmp.c_str(), pos);
assert(pos >= 0);
out_list.push_back(ConvertFileInfo(tmp.substr(pos, std::string::npos), files[i]));
}
hdfsFreeFileInfo(files, nentry);
}
}

Просмотреть файл

@ -1,90 +0,0 @@
#include "io.h"
#include "hdfs_file_sys.h"
#include "local_file_sys.h"
namespace multiverso
{
FileSystem *FileSystem::GetInstance(const std::string type,
const std::string host)
{
std::string type_tmp = type;
if (type.length() == 0)
type_tmp = "file";
if (instances_.find(make_pair(type_tmp, host)) != instances_.end())
return instances_[make_pair(type_tmp, host)];
if (type_tmp == std::string("file"))
return instances_[make_pair(type_tmp, host)] = new LocalFileSystem(host);
if (type_tmp == std::string("hdfs"))
return instances_[make_pair(type_tmp, host)] = new HDFSFileSystem(host);
Log::Error("Can not support the FileSystem '%s'\n", type.c_str());
}
std::map<std::pair<std::string, std::string>, FileSystem *> FileSystem::instances_;
FileSystem::~FileSystem()
{
for (auto &p : instances_)
p.second->Close();
instances_.clear();
}
TextReader::TextReader(Stream *stream, size_t buf_size)
{
stream_ = stream;
buf_size_ = buf_size;
pos_ = length_ = 0;
buf_ = new char[buf_size_];
assert(buf_ != nullptr);
}
size_t TextReader::GetLine(char *line)
{
Log::Debug("TextReader begin read\n");
size_t ret = 0;
bool isEnd = false;
while (true)
{
while(pos_ < length_)
{
char & c = buf_[pos_++];
if (c == '\n')
{
isEnd = true;
break;
}
else
{
line[ret++] = c;
}
}
// has read '\n' or the end of Stream
if (isEnd || LoadBuffer() == 0)
{
break;
}
}
//Log::Debug("TextReader read %d bytes\n", ret);
line[ret] = '\0';
return ret;
}
size_t TextReader::LoadBuffer()
{
assert (pos_ == length_);
pos_ = length_ = 0;
return length_ = stream_->Read(buf_, buf_size_);
}
TextReader::~TextReader()
{
delete [] buf_;
}
}

Просмотреть файл

@ -1,218 +0,0 @@
#include "local_file_sys.h"
#include <errno.h>
extern "C" {
#include <sys/stat.h>
}
#ifndef _MSC_VER
extern "C" {
#include <sys/types.h>
#include <dirent.h>
}
#else
#include <Windows.h>
#define stat _stat64
#endif
namespace multiverso
{
LocalStream::LocalStream(FILE * fp, std::string path)
{
fp_ = fp;
path_ = path;
}
LocalStream::~LocalStream()
{
if (fp_ != nullptr)
std::fclose(fp_);
}
/*!
* \brief write data to a file
* \param buf pointer to a memory buffer
* \param size data size
*/
void LocalStream::Write(const void *buf, size_t size)
{
if (std::fwrite(buf, 1, size, fp_) != size)
{
Log::Error("LocalStream.Write incomplete\n");
}
}
/*!
* \brief read data from Stream
* \param buf pointer to a memory buffer
* \param size the size of buf
*/
size_t LocalStream::Read(void *buf, size_t size)
{
return std::fread(buf, 1, size, fp_);
}
/*!
* \brief move the position point to seekOrigin + offset
* \param offset the offset(bytes number) to change the position point
* \param seekOrigin the reference position
*/
void LocalStream::Seek(size_t offset, SeekOrigin seekOrigin)
{
if (seekOrigin == SeekOrigin::kBegin)
std::fseek(fp_, static_cast<long>(offset), SEEK_SET);
else if (seekOrigin == SeekOrigin::kCurrent)
std::fseek(fp_, static_cast<long>(offset), SEEK_CUR);
else
std::fseek(fp_, static_cast<long>(offset), SEEK_END);
}
/*!
* \brief flush local buffer
*/
void LocalStream::Flush()
{
std::fflush(fp_);
}
LocalFileSystem::LocalFileSystem(std::string host)
{
host_ = host;
}
/*!
* \brief create a Stream
* \param path the path of the file
* \param mode "w" - create an empty file to store data;
* "a" - open the file to append data to it
* "r" - open the file to read
* \return the Stream which is used to write or read data
*/
Stream * LocalFileSystem::Open(const std::string path,
const char *mode)
{
FILE *fp = fopen(path.c_str(), mode);
if (fp == nullptr)
{
Log::Error("Failed to open LocalStream %s\n", path.c_str());
return nullptr;
}
else
return new LocalStream(fp, path);
}
void LocalFileSystem::CreateDirectory(const std::string path)
{
}
/*!
* \brief check if the path exists
* \param path the file or directory
*/
bool LocalFileSystem::Exists(const std::string path)
{
///TODO
}
/*!
* \brief delete the file or directory
* \param path the file or directory
*/
void LocalFileSystem::Delete(const std::string path)
{
///TODO
}
FileInfo *LocalFileSystem::GetPathInfo(const std::string path)
{
struct stat sb;
if (stat(path.c_str(), &sb) == -1)
{
int errsv = errno;
Log::Fatal("Failed to GetPathInfo %s: %s\n",
path.c_str(), strerror(errsv));
}
FileInfo *ret = new FileInfo();
ret->path = path;
ret->size = sb.st_size;
if ((sb.st_mode & S_IFMT) == S_IFDIR)
ret->type = FileType::kDirectory;
else
ret->type = FileType::kFile;
return ret;
}
void LocalFileSystem::Rename(const std::string old_path, const std::string new_path)
{
///TODO
}
void LocalFileSystem::Copy(const std::string src, const std::string dst)
{
///TODO
}
void LocalFileSystem::Close()
{
///TODO
}
void LocalFileSystem::ListDirectory(const std::string path, std::vector<FileInfo*> & out_list)
{
#ifndef _MSC_VER
DIR *dir = opendir(path.c_str());
if (dir == NULL)
{
int errsv = errno;
Log::Fatal("Failed to ListDirectory %s, %s\n",
path.c_str(), strerror(errsv));
}
out_list.clear();
struct dirent *ent;
while ((ent = readdir(dir)) != nullptr)
{
if (!strcmp(ent->d_name, ".")) continue;
if (!strcmp(ent->d_name, "..")) continue;
std::string pp = path;
if (pp[pp.length() - 1] != '/') {
pp += '/';
}
pp += ent->d_name;
out_list.push_back(GetPathInfo(pp));
}
closedir(dir);
#else
WIN32_FIND_DATA fd;
std::string pattern = path + "/*";
HANDLE handle = FindFirstFile(pattern.c_str(), &fd);
if (handle == INVALID_HANDLE_VALUE)
{
int errsv = GetLastError();
Log::Fatal("Failed to ListDirectory %s: %s\n",
path.c_str(), strerror(errsv));
}
out_list.clear();
do
{
if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, ".."))
{
std::string pp = path;
char clast = pp[pp.length() - 1];
if (pp == ".")
{
pp.name = fd.cFileName;
} else if (clast != '/' && clast != '\\') {
pp += '/';
pp += fd.cFileName;
}
out_list.push_back(GetPathInfo(pp));
}
} while (FindNextFile(handle, &fd));
FindClose(handle);
#endif
}
}

Просмотреть файл

@ -1,37 +0,0 @@
#include "lock.h"
namespace multiverso
{
#if defined(_WIN32) || defined(_WIN64)
// Defines the Windows' version Mutex which wraps a CRITICAL_SECTION object.
class Mutex
{
public:
Mutex() { InitializeCriticalSection(&mutex_); }
~Mutex() { DeleteCriticalSection(&mutex_); }
void Lock() { EnterCriticalSection(&mutex_); }
void Unlock() { LeaveCriticalSection(&mutex_); }
private:
CRITICAL_SECTION mutex_;
};
#else
// In other systems, class Mutex is a wrapper if C++ standard mutex object.
class Mutex
{
public:
Mutex() {}
~Mutex() {}
void Lock() { mutex_.lock(); }
void Unlock() { mutex_.unlock(); }
private:
std::mutex mutex_;
};
#endif
LockManager::LockManager(int num_lock) : locks_(num_lock) { }
LockManager::~LockManager() {}
void LockManager::Lock(int id) { locks_[id % locks_.size()].Lock(); }
void LockManager::Unlock(int id) { locks_[id % locks_.size()].Unlock(); }
int LockManager::Size() { return static_cast<int>(locks_.size()); }
}

Просмотреть файл

@ -1,205 +0,0 @@
#include <ctime>
#include <cstdarg>
#include "log.h"
namespace multiverso
{
//-- Begin of Logger rountine --------------------------------------------/
// Creates a Logger intance writing messages into STDOUT.
Logger::Logger(LogLevel level)
{
level_ = level;
file_ = nullptr;
}
// Creates a Logger instance writing messages into both STDOUT and log file.
Logger::Logger(std::string filename, LogLevel level)
{
level_ = level;
file_ = nullptr;
ResetLogFile(filename);
}
Logger::~Logger()
{
CloseLogFile();
}
int Logger::ResetLogFile(std::string filename)
{
CloseLogFile();
if (filename.size() > 0) // try to open the log file if it is specified
{
file_ = fopen(filename.c_str(), "w");
if (file_ == nullptr)
{
Error("Cannot create log file %s\n", filename.c_str());
return -1;
}
}
return 0;
}
void Logger::Write(LogLevel level, const char *format, ...)
{
va_list val;
va_start(val, format);
Write(level, format, val);
va_end(val);
}
void Logger::Debug(const char *format, ...)
{
va_list val;
va_start(val, format);
Write(LogLevel::Debug, format, val);
va_end(val);
}
void Logger::Info(const char *format, ...)
{
va_list val;
va_start(val, format);
Write(LogLevel::Info, format, val);
va_end(val);
}
void Logger::Error(const char *format, ...)
{
va_list val;
va_start(val, format);
Write(LogLevel::Error, format, val);
va_end(val);
}
void Logger::Fatal(const char *format, ...)
{
va_list val;
va_start(val, format);
Write(LogLevel::Fatal, format, val);
va_end(val);
}
// TODO and DISCUSSION (thread safety issue): Two printing methods are
// called for writing a message: one for printing the header information
// and the other for printing the content. When multiple threads call the
// method simultaneously, there may be missed-order problem.
inline void Logger::Write(LogLevel level, const char *format, va_list &val)
{
if (level >= level_) // omit the message with low level
{
std::string level_str = GetLevelStr(level);
std::string time_str = GetSystemTime();
va_list val_copy;
va_copy(val_copy, val);
// write to STDOUT
printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
vprintf(format, val);
fflush(stdout);
// write to log file
if (file_ != nullptr)
{
fprintf(file_, "[%s] [%s] ", level_str.c_str(), time_str.c_str());
vfprintf(file_, format, val_copy);
fflush(file_);
}
va_end(val_copy);
if (is_kill_fatal_ && level == LogLevel::Fatal)
{
CloseLogFile();
exit(1);
}
}
}
// Closes the log file if it it not null.
void Logger::CloseLogFile()
{
if (file_ != nullptr)
{
fclose(file_);
file_ = nullptr;
}
}
std::string Logger::GetSystemTime()
{
time_t t = time(0);
char str[64];
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
return str;
}
std::string Logger::GetLevelStr(LogLevel level)
{
switch (level)
{
case LogLevel::Debug: return "DEBUG";
case LogLevel::Info: return "INFO";
case LogLevel::Error: return "ERROR";
case LogLevel::Fatal: return "FATAL";
default: return "UNKNOW";
}
}
//-- End of Logger rountine ----------------------------------------------/
// Begin of Log class rountine -------------------------------------------/
Logger Log::logger_; // global (in process) static Logger instance
int Log::ResetLogFile(std::string filename)
{
return logger_.ResetLogFile(filename);
}
void Log::ResetLogLevel(LogLevel level)
{
logger_.ResetLogLevel(level);
}
void Log::ResetKillFatal(bool is_kill_fatal)
{
logger_.ResetKillFatal(is_kill_fatal);
}
void Log::Write(LogLevel level, const char *format, ...)
{
va_list val;
va_start(val, format);
logger_.Write(level, format, val);
va_end(val);
}
void Log::Debug(const char *format, ...)
{
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Debug, format, val);
va_end(val);
}
void Log::Info(const char *format, ...)
{
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Info, format, val);
va_end(val);
}
void Log::Error(const char *format, ...)
{
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Error, format, val);
va_end(val);
}
void Log::Fatal(const char *format, ...)
{
va_list val;
va_start(val, format);
logger_.Write(LogLevel::Fatal, format, val);
va_end(val);
}
// End of Log class rountine ---------------------------------------------/
}

Просмотреть файл

@ -1,149 +0,0 @@
#include "msg_pack.h"
#include "mpi_util.h"
//#include <exception>
//#include "log.h" // temporary include
namespace multiverso
{
//-- area of static member definition ------------------------------------/
int MPIUtil::mpi_size_ = 0;
int MPIUtil::mpi_rank_ = 0;
std::queue<std::shared_ptr<MsgPack>> MPIUtil::send_queue_;
#if defined (_MPI_VERSION_)
char MPIUtil::recv_buffer_[kMPIBufferSize];
MPI_Request MPIUtil::recv_request_ = MPI_REQUEST_NULL;
char MPIUtil::send_buffer_[kMPIBufferSize];
MPI_Request MPIUtil::send_request_ = MPI_REQUEST_NULL;
#endif
//-- end of static member definition -------------------------------------/
#if defined (_MPI_VERSION_)
// Initializes MPI environment
void MPIUtil::Init(int *argc, char **argv[])
{
int flag = 0;
MPI_Initialized(&flag); // test if MPI has been initialized
if (!flag) // if MPI not started, start it
{
MPI_Init_thread(argc, argv, MPI_THREAD_SERIALIZED, &flag);
}
MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_);
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_);
}
// Finalizes MPI environment
void MPIUtil::Close()
{
MPI_Finalize();
}
std::shared_ptr<MsgPack> MPIUtil::ProbeAndRecv()
{
int flag;
MPI_Status status;
// test if there is new message comes
MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
if (flag) // MPI message arrived
{
MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
status.MPI_TAG, MPI_COMM_WORLD, &status);
std::shared_ptr<MsgPack> request(
new MsgPack(recv_buffer_, status.count));
return request;
}
return nullptr;
}
//// Try to receive messages with MPI non-blocking receiving method.
//std::shared_ptr<MsgPack> MPIUtil::MPIProbe()
//{
// try{
// int flag;
// MPI_Status status;
// // if there is message being received
// if (recv_request_ != MPI_REQUEST_NULL)
// {
// // test if the receiving completed
// MPI_Test(&recv_request_, &flag, &status);
// if (flag) // recv completed, deserialize the data into ZMQ messages
// {
// recv_request_ = MPI_REQUEST_NULL;
// std::shared_ptr<MsgPack> request(
// new MsgPack(recv_buffer_, status.count));
// return request;
// }
// else // recv not completed yet
// {
// return nullptr;
// }
// }
// // test if there is new message comes
// MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
// if (flag) // MPI message arrived
// {
// //MPI_Irecv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
// // status.MPI_TAG, MPI_COMM_WORLD, &recv_request_);
// MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
// status.MPI_TAG, MPI_COMM_WORLD, &status);
// std::shared_ptr<MsgPack> request(new MsgPack(recv_buffer_, status.count));
// return request;
// }
// return nullptr;
// }
// catch (std::exception e)
// {
// Log::Error("Rank=%d Probe\n", mpi_rank_);
// throw e;
// }
//}
// Send messages with MPI non-blocking sending method. Actually, it pushes
// the message into the queue (if not null), test if last sending has
// been completed, and send a new one in the queue if so.
void MPIUtil::Send(std::shared_ptr<MsgPack> msg_pack)
{
static int tag = 0;
// push the send message into the send queue
if (msg_pack.get() != nullptr)
{
send_queue_.push(msg_pack);
}
// test if the last send has been completed, return immediately if not
if (send_request_ != MPI_REQUEST_NULL)
{
MPI_Status status;
int flag;
MPI_Test(&send_request_, &flag, &status);
if (flag) // send completed
{
send_request_ = MPI_REQUEST_NULL;
}
else
{
return;
}
}
// if there is message in the send queue, send it
if (!send_queue_.empty())
{
MsgType msg_type;
MsgArrow msg_arrow;
int src, dst, size;
std::shared_ptr<MsgPack> msg_send = send_queue_.front();
send_queue_.pop();
msg_send->GetHeaderInfo(&msg_type, &msg_arrow, &src, &dst);
// serialize the message into MPI send buffer
msg_send->Serialize(send_buffer_, &size);
MPI_Isend(send_buffer_, size, MPI_BYTE, dst, tag++, MPI_COMM_WORLD,
&send_request_);
}
}
#endif
}

Просмотреть файл

@ -1,138 +0,0 @@
#include "zmq.hpp"
#include "msg_pack.h"
namespace multiverso
{
// Creates an empty MsgPack.
MsgPack::MsgPack() { start_ = 0; }
// Creates a MsgPack with header information
MsgPack::MsgPack(MsgType type, MsgArrow arrow, int src, int dst)
{
start_ = 0;
Push(new zmq::message_t(0));
zmq::message_t *header = new zmq::message_t(4 * sizeof(int));
int *buffer = static_cast<int*>(header->data());
buffer[0] = static_cast<int>(type);
buffer[1] = static_cast<int>(arrow);
buffer[2] = src;
buffer[3] = dst;
Push(header);
}
// Receives a multiple message from the socket and push into this MsgPack
MsgPack::MsgPack(zmq::socket_t *socket)
{
start_ = 0;
while (true)
{
zmq::message_t *msg = new zmq::message_t();
socket->recv(msg);
Push(msg);
if (!msg->more())
{
break;
}
}
}
// Deserializes the data block and composes a MsgPack.
MsgPack::MsgPack(char *buffer, int size)
{
start_ = 0;
int msg_size = 0;
for (int pos = 0; pos < size;)
{
// get the message size
memcpy(&msg_size, buffer + pos, sizeof(int));
pos += sizeof(int);
// copy the message content
zmq::message_t *msg = new zmq::message_t(msg_size);
memcpy(msg->data(), buffer + pos, msg_size);
Push(msg);
pos += msg_size;
}
}
MsgPack::~MsgPack()
{
for (auto &msg : messages_)
{
delete msg;
}
}
// Pushes a message into back of the array
void MsgPack::Push(zmq::message_t *msg)
{
messages_.push_back(msg);
if (start_ == 0 && msg->size() == 0)
{
start_ = static_cast<int>(messages_.size());
}
}
// Copies the header information
void MsgPack::GetHeaderInfo(MsgType *type, MsgArrow *arrow, int *src, int *dst)
{
int *buffer = static_cast<int*>(messages_[start_]->data());
*type = static_cast<MsgType>(buffer[0]);
*arrow = static_cast<MsgArrow>(buffer[1]);
*src = buffer[2];
*dst = buffer[3];
}
// Sends the messages with the socket
void MsgPack::Send(zmq::socket_t *socket)
{
int size = static_cast<int>(messages_.size()), more;
for (int i = 0; i < size; ++i)
{
more = (i < size - 1) ? ZMQ_SNDMORE : 0;
socket->send(*messages_[i], more);
}
}
// Creates reply message (address + header)
MsgPack *MsgPack::CreateReplyMsgPack()
{
MsgPack *reply = new MsgPack();
// copy addresses
for (int i = 0; i < start_; ++i)
{
zmq::message_t *addr = new zmq::message_t(messages_[i]->size());
memcpy(addr->data(), messages_[i]->data(), messages_[i]->size());
reply->Push(addr);
}
// construct the reply header
int *my_header = static_cast<int*>(messages_[start_]->data());
zmq::message_t *header = new zmq::message_t(4 * sizeof(int));
int *buffer = static_cast<int*>(header->data());
buffer[0] = -my_header[0]; // reply message type
buffer[1] = 1 - my_header[1]; // worker <--> server
buffer[2] = my_header[3]; // src <--> dst
buffer[3] = my_header[2];
reply->Push(header);
return reply;
}
// Serializes the messages into the binary data block.
void MsgPack::Serialize(char *buffer, int *size)
{
*size = 0;
char *buf = buffer;
int64_t count = messages_.size();
int piece_size = 0;
for (int64_t i = 0; i < count; ++i)
{
// copy the message size first
piece_size = static_cast<int>(messages_[i]->size());
memcpy(buf, &piece_size, sizeof(int));
buf += sizeof(int);
// then copy the message content
memcpy(buf, messages_[i]->data(), piece_size);
buf += piece_size;
(*size) += piece_size + sizeof(int);
}
}
}

Просмотреть файл

@ -1,410 +0,0 @@
#include <algorithm>
#include "zmq.hpp"
#include "log.h"
#include "lock.h"
#include "msg_pack.h"
#include "communicator.h"
#include "aggregator.h"
#include "server.h"
#include "double_buffer.h"
#include "zmq_util.h"
#include "multiverso.h"
namespace multiverso
{
//-- Static member definition area ---------------------------------------/
RegisterInfo Multiverso::reg_info_;
int Multiverso::num_trainers_;
zmq::socket_t *Multiverso::socket_ = nullptr;
LockManager *Multiverso::lock_manager_ = nullptr;
LockOption Multiverso::lock_option_ = LockOption::Immutable;
Communicator *Multiverso::communicator_ = nullptr;
IAggregator *Multiverso::aggregator_ = nullptr;
bool Multiverso::is_pipeline_ = true;
Barrier* Multiverso::pipeline_barrier_ = nullptr;
std::vector<TrainerBase*> Multiverso::trainers_;
ParameterLoaderBase *Multiverso::param_loader_ = nullptr;
std::vector<Table*> Multiverso::tables0_;
std::vector<Table*> Multiverso::tables1_;
DoubleBuffer<std::vector<Table*>> *Multiverso::double_buffer_ = nullptr;
std::mutex Multiverso::mutex_;
std::condition_variable Multiverso::wait_cv_;
std::vector<bool> Multiverso::data_tag_;
std::vector<MsgPack*> Multiverso::row_config_;
std::vector<int> Multiverso::row_config_size_;
int Multiverso::row_config_count_ = 0;
//-- End of static member definition area --------------------------------/
// Initializes Multiverso environment
int Multiverso::Init(std::vector<TrainerBase*> &trainers,
ParameterLoaderBase *param_loader, const Config &config,
int *argc, char **argv[])
{
#if defined (_MULTIVERSO_DEBUG_)
Log::ResetLogLevel(LogLevel::Debug);
#endif
int ret = 0;
num_trainers_ = static_cast<int>(trainers.size());
// Starts the background communicator
communicator_ = new Communicator(config, argc, argv);
socket_ = communicator_->CreateSocket();
reg_info_ = communicator_->Register(socket_, config, num_trainers_);
// Starts the background aggregator
aggregator_ = IAggregator::CreateAggregator(
config.num_aggregator, config.num_trainers);//new Aggregator(config.num_aggregator, num_trainers_);
row_config_.resize(reg_info_.server_count, nullptr);
row_config_size_.resize(reg_info_.server_count, 0);
is_pipeline_ = config.is_pipeline;
pipeline_barrier_ = is_pipeline_ ? nullptr : new Barrier(num_trainers_+1);
// prepare local data structures
data_tag_.resize(trainers.size());
trainers_ = trainers;
param_loader_ = param_loader;
double_buffer_ = new DoubleBuffer<std::vector<Table*>>(
static_cast<int>(trainers.size()), &tables0_, &tables1_);
if ((lock_option_ = config.lock_option) == LockOption::Locked)
{
lock_manager_ = new LockManager(std::max<int>(config.num_lock, 1));
}
if (ret == 0)
{
Log::Info("Rank %d/%d: Multiverso initialized successfully.\n",
reg_info_.proc_rank, reg_info_.proc_count);
}
return ret;
}
int Multiverso::Init(const Config &config, int *argc, char **argv[])
{
#if defined (_MULTIVERSO_DEBUG_)
Log::ResetLogLevel(LogLevel::Debug);
#endif
int ret = 0;
num_trainers_ = static_cast<int>(config.num_trainers);
// Starts the background communicator
communicator_ = new Communicator(config, argc, argv);
socket_ = communicator_->CreateSocket();
reg_info_ = communicator_->Register(socket_, config, num_trainers_);
// Starts the background aggregator
aggregator_ = IAggregator::CreateAggregator(
config.num_aggregator, config.num_trainers);
row_config_.resize(reg_info_.server_count, nullptr);
row_config_size_.resize(reg_info_.server_count, 0);
// prepare local data structures
double_buffer_ = new DoubleBuffer<std::vector<Table*>>(
static_cast<int>(num_trainers_), &tables0_, &tables1_);
if ((lock_option_ = config.lock_option) == LockOption::Locked)
{
lock_manager_ = new LockManager(std::max<int>(config.num_lock, 1));
}
if (ret == 0)
{
Log::Info("Rank %d/%d: Multiverso initialized successfully.\n",
reg_info_.proc_rank, reg_info_.proc_count);
}
return ret;
}
// Close Multiverso environment
void Multiverso::Close(bool finalize)
{
// Sends close message to all servers
for (int server = 0; server < reg_info_.server_count; ++server)
{
MsgPack msg(MsgType::Close, MsgArrow::Worker2Server,
reg_info_.proc_rank, server);
msg.Send(socket_);
}
for (int server = 0; server < reg_info_.server_count; ++server)
{
MsgPack reply(socket_);
}
delete socket_;
// close the background threads
delete aggregator_;
communicator_->SetMPIFinalize(finalize);
delete communicator_;
// delete data structures
delete double_buffer_;
for (int i = 0; i < tables0_.size(); ++i)
{
delete tables0_[i];
delete tables1_[i];
}
tables0_.clear();
tables1_.clear();
if (lock_manager_)
{
delete lock_manager_;
lock_manager_ = nullptr;
}
Log::Info("Rank %d/%d: Multiverso closed successfully.\n",
reg_info_.proc_rank, reg_info_.proc_count);
}
void Multiverso::BeginConfig()
{
Log::Info("Rank %d/%d: Begin of configuration and initialization.\n",
reg_info_.proc_rank, reg_info_.proc_count);
}
// Global barrier at the end of initialization
void Multiverso::EndConfig()
{
FlushSetServerRow();
// Send flush and clock signal to aggregator, let the aggregator send
// the update to server.
for (int trainer = 0; trainer < num_trainers_; ++trainer)
{
aggregator_->Flush(trainer); // Add(trainer, 0, -1, 0, nullptr); // flush
aggregator_->Clock(trainer); // Add(trainer, 0, -2, 0, nullptr); // clock
}
aggregator_->Wait();
// Send barrier messages to all servers
// DISCUSSION: it may be better to let the Aggregator to do the barrier.
for (int server = 0; server < reg_info_.server_count; ++server)
{
MsgPack msg(MsgType::Barrier, MsgArrow::Worker2Server,
reg_info_.proc_rank, server);
msg.Send(socket_);
}
// wait for replies
for (int server = 0; server < reg_info_.server_count; ++server)
{
MsgPack reply(socket_);
}
Log::Info("Rank %d/%d: End of configration and initialization.\n",
reg_info_.proc_rank, reg_info_.proc_count);
}
void Multiverso::AddTable(integer_t table, integer_t rows, integer_t cols,
Type type, Format default_format, int64_t memory_pool_size)
{
AddServerTable(table, rows, cols, type, default_format);
AddCacheTable(
table, rows, cols, type, default_format, memory_pool_size);
AddAggregatorTable(
table, rows, cols, type, default_format, memory_pool_size);
}
// Sends messages to each server for creating a server table.
void Multiverso::AddServerTable(integer_t table, integer_t rows,
integer_t cols, Type type, Format default_format)
{
for (int server = 0; server < reg_info_.server_count; ++server)
{
MsgPack msg_pack(MsgType::CreateTable, MsgArrow::Worker2Server,
reg_info_.proc_rank, server);
zmq::message_t *msg =
new zmq::message_t(3 * sizeof(integer_t) + 2 * sizeof(int));
integer_t *buf = static_cast<integer_t*>(msg->data());
buf[0] = table; // table id
buf[1] = rows; // rows
buf[2] = cols; // cols
int *buf_i = static_cast<int*>(buf + 3);
buf_i[0] = static_cast<int>(type); // type
buf_i[1] = static_cast<int>(default_format); // default_format
msg_pack.Push(msg);
msg_pack.Send(socket_);
}
}
// Creates local cache tables for double buffer
int Multiverso::AddCacheTable(integer_t table, integer_t rows, integer_t cols,
Type type, Format default_format, int64_t memory_pool_size)
{
if (table == tables0_.size())
{
tables0_.push_back(new Table(
table, rows, cols, type, default_format, memory_pool_size));
tables1_.push_back(new Table(
table, rows, cols, type, default_format, memory_pool_size));
return 0;
}
return -1;
}
// Creates aggregator table
void Multiverso::AddAggregatorTable(integer_t table, integer_t rows,
integer_t cols, Type type, Format default_format,
int64_t memory_pool_size)
{
aggregator_->CreateTable(
table, rows, cols, type, default_format, memory_pool_size);
}
// The unified method of setting a row.
void Multiverso::SetRow(integer_t table, integer_t row, Format format,
integer_t capacity)
{
SetServerRow(table, row, format, capacity);
SetCacheRow(table, row, format, capacity);
SetAggregatorRow(table, row, format, capacity);
}
// Caches a server row setting message and sends them to the server if the
// message pack is large enough.
void Multiverso::SetServerRow(integer_t table, integer_t row,
Format format, integer_t capacity)
{
int server = (table + row) % reg_info_.server_count;
if (row_config_[server] == nullptr)
{
row_config_[server] = new MsgPack(MsgType::SetRow,
MsgArrow::Worker2Server, reg_info_.proc_rank, server);
++row_config_count_;
}
int size = 3 * sizeof(integer_t)+sizeof(int);
zmq::message_t *msg = new zmq::message_t(size);
integer_t *buf = static_cast<integer_t*>(msg->data());
buf[0] = table; // table_id
buf[1] = row; // row_id
buf[2] = capacity; // capacity
memcpy(buf + 3, &format, sizeof(int)); // format
row_config_[server]->Push(msg);
row_config_size_[server] += size;
if (row_config_size_[server] >= kMaxMsgSize)
{
row_config_[server]->Send(socket_);
delete row_config_[server];
row_config_[server] = nullptr;
row_config_size_[server] = 0;
--row_config_count_;
}
}
void Multiverso::FlushSetServerRow()
{
for (int server = 0; server < reg_info_.server_count; ++server)
{
if (row_config_[server] != nullptr)
{
row_config_[server]->Send(socket_);
delete row_config_[server];
row_config_[server] = nullptr;
row_config_size_[server] = 0;
--row_config_count_;
}
}
}
// Configures a row in cache.
int Multiverso::SetCacheRow(integer_t table, integer_t row,
Format format, integer_t capacity)
{
int ret0 = tables0_[table]->SetRow(row, format, capacity);
int ret1 = tables1_[table]->SetRow(row, format, capacity);
return (ret0 < 0 || ret1 < 0) ? -1 : 0;
}
// Configures a row in aggregator.
int Multiverso::SetAggregatorRow(integer_t table, integer_t row,
Format format, integer_t capacity)
{
return aggregator_->SetAggregatorRow(table, row, format, capacity);
}
void Multiverso::AddToServerPtr(
integer_t table, integer_t row, integer_t col, void *delta)
{
if (row_config_count_ > 0)
{
FlushSetServerRow();
}
aggregator_->Add(0, table, row, col, delta);
}
void Multiverso::Flush()
{
for (int trainer = 0; trainer < trainers_.size(); ++trainer)
{
aggregator_->Flush(trainer); // Add(trainer, 0, -1, 0, nullptr); // flush
}
}
// Begin training
void Multiverso::BeginTrain()
{
Log::Info("Rank %d/%d: Begin of training.\n",
reg_info_.proc_rank, reg_info_.proc_count);
param_loader_->Start();
for (auto &trainer : trainers_)
{
trainer->Start();
}
}
// End training
void Multiverso::EndTrain()
{
// REMARK(feiyan): should make sure that the param loader and trainers
// consumed all the data
// REMARK(feiga): the stop order is important
param_loader_->Stop();
for (auto &trainer : trainers_)
{
trainer->Stop();
}
MsgPack msg(MsgType::EndTrain, MsgArrow::Worker2Server,
reg_info_.proc_rank, 0);
msg.Send(socket_);
Log::Info("Rank %d/%d: End of training.\n",
reg_info_.proc_rank, reg_info_.proc_count);
}
void Multiverso::BeginClock()
{
static DataBlockBase begin_clock(DataBlockType::BeginClock);
PushDataBlock(&begin_clock);
}
void Multiverso::EndClock()
{
static DataBlockBase end_clock(DataBlockType::EndClock);
PushDataBlock(&end_clock);
}
void Multiverso::PushDataBlock(DataBlockBase *data_block)
{
// mark the data block as being processed
data_block->IncreaseCount(1);
param_loader_->PushDataBlock(data_block);
for (auto &trainer : trainers_)
{
trainer->PushDataBlock(data_block);
}
}
void Multiverso::Wait()
{
std::unique_lock<std::mutex> lock(mutex_);
wait_cv_.wait(lock, [] {
for (auto tag : data_tag_) if (!tag) return false;
return true;
});
}
}

Просмотреть файл

@ -1,200 +0,0 @@
#include "parameter_loader.h"
#include "double_buffer.h"
#include "log.h"
#include "msg_pack.h"
#include "multiverso.h"
#include "zmq_util.h"
namespace multiverso{
ParameterLoaderBase::ParameterLoaderBase()
{
}
ParameterLoaderBase::~ParameterLoaderBase()
{
}
void ParameterLoaderBase::PushDataBlock(DataBlockBase *data_block)
{
data_queue_.Push(data_block);
}
void ParameterLoaderBase::RequestTable(integer_t table)
{
requests_.insert({ table, -1, -1 });
}
void ParameterLoaderBase::RequestRow(integer_t table, integer_t row)
{
if (requests_.find({ table, -1, -1 }) == requests_.end())
{
requests_.insert({ table, row, -1 });
}
}
void ParameterLoaderBase::RequestElement(integer_t table,
integer_t row, integer_t col)
{
if (requests_.find({ table, -1, -1 }) == requests_.end() &&
requests_.find({ table, row, -1 }) == requests_.end())
{
requests_.insert({ table, row, col });
}
}
void ParameterLoaderBase::ParseAndRequest(DataBlockBase* data_block)
{
Log::Fatal("You need to override this method\n");
}
void ParameterLoaderBase::StartThread()
{
DataBlockBase* data_block;
while (data_queue_.Pop(data_block))
{
if (!Multiverso::is_pipeline_)
{
Multiverso::pipeline_barrier_->Wait();
}
if (data_block->Type() != DataBlockType::BeginClock
&& data_block->Type() != DataBlockType::EndClock) // skip Clock
{
BeginIteration();
requests_.clear();
// Parse data block
ParseAndRequest(data_block);
ProcessRequest();
EndIteration();
}
if (!Multiverso::is_pipeline_)
{
Multiverso::pipeline_barrier_->Wait();
}
}
if (!Multiverso::is_pipeline_)
{
Multiverso::pipeline_barrier_->Wait();
}
}
void ParameterLoaderBase::Start()
{
loader_thread_ = std::thread(&ParameterLoaderBase::StartThread, this);
}
void ParameterLoaderBase::Stop()
{
data_queue_.Exit();
loader_thread_.join();
}
// Underlying implemention of parameter request
void ParameterLoaderBase::ProcessRequest()
{
zmq::socket_t *socket = ZMQUtil::CreateSocket();
std::vector<Table*>& cache =
Multiverso::double_buffer_->IOBuffer();
for (int i = 0; i < cache.size(); ++i)
{
cache[i]->Clear();
}
int src_rank = Multiverso::ProcessRank();
int num_server = Multiverso::TotalServerCount();
std::vector<MsgPack*> send_list(num_server, nullptr);
std::vector<int> send_ret_size(num_server, 0);
int num_send_msg = 0;
for (auto tuple : requests_)
{
integer_t table = tuple.table;
integer_t row = tuple.row;
integer_t col = tuple.col;
if (row >= 0 && requests_.find({ table, -1, -1 }) != requests_.end() ||
col >= 0 && requests_.find({ table, row, -1 }) != requests_.end())
{
continue;
}
int dst_rank, last_rank;
if (row == -1)
{
dst_rank = 0;
last_rank = num_server - 1;
}
else
{
dst_rank = (table + row) % num_server;
last_rank = dst_rank;
}
while (dst_rank <= last_rank)
{
if (send_list[dst_rank] == nullptr)
{
send_list[dst_rank] = new MsgPack(MsgType::Get,
MsgArrow::Worker2Server, src_rank, dst_rank);
send_ret_size[dst_rank] = 0;
}
if (send_ret_size[dst_rank] + 3 * sizeof(integer_t) > kMaxMsgSize)
{
send_list[dst_rank]->Send(socket);
++num_send_msg;
delete send_list[dst_rank];
send_list[dst_rank] = new MsgPack(MsgType::Get,
MsgArrow::Worker2Server, src_rank, dst_rank);
send_ret_size[dst_rank] = 0;
}
zmq::message_t* msg = new zmq::message_t(3 * sizeof(integer_t));
integer_t* buffer = static_cast<integer_t*>(msg->data());
buffer[0] = table;
buffer[1] = row;
buffer[2] = col;
send_list[dst_rank]->Push(msg);
send_ret_size[dst_rank] += 3 * sizeof(integer_t);
++dst_rank;
}
}
for (int i = 0; i < num_server; ++i)
{
if (send_ret_size[i] > 0)
{
send_list[i]->Send(socket);
++num_send_msg;
delete send_list[i];
}
}
// we expect each ReplyGet msg contains a over tag.
while (num_send_msg > 0)
{
MsgPack reply(socket);
for (int i = 1; i < reply.Size() - 1; ++i)
{
zmq::message_t* msg = reply.GetMsg(i);
integer_t *buffer = static_cast<integer_t*>(msg->data());
integer_t table = buffer[0];
integer_t row = buffer[1];
cache[table]->GetRow(row)->BatchAdd(buffer + 2);
}
zmq::message_t* msg = reply.GetMsg(reply.Size() - 1);
bool over = (static_cast<integer_t*>(msg->data())[0] == 1);
if (over)
{
--num_send_msg;
}
}
delete socket;
}
void ParameterLoaderBase::BeginIteration()
{
Multiverso::double_buffer_->Start(0);
}
void ParameterLoaderBase::EndIteration()
{
Multiverso::double_buffer_->End(0);
}
}

Просмотреть файл

@ -1,391 +0,0 @@
#include "row.h"
#include "row_iter.h"
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <cmath>
#include <unordered_map>
namespace multiverso
{
//-- Row stuff definition ------------------------------------------------/
template <typename T>
Row<T>::Row(integer_t row_id, Format format, integer_t capacity, void* memory)
: row_id_(row_id), format_(format), capacity_(capacity), memory_(memory),
nonzero_size_(0), num_deleted_key_(0), has_memory_(false)
{
if (format_ == Format::Dense)
{
if (memory_ == nullptr)
{
has_memory_ = true;
memory_ = malloc(capacity * sizeof(T));
}
value_ = reinterpret_cast<T*>(memory_);
memset(memory_, 0, capacity_ * sizeof(T));
}
else // format_ == Format::Sparse
{
if (memory_ == nullptr)
{
has_memory_ = true;
memory_ = malloc(capacity * (sizeof(integer_t)+sizeof(T)));
}
key_ = reinterpret_cast<integer_t*>(memory_);
memset(key_, 0, capacity_ * sizeof(integer_t));
value_ = reinterpret_cast<T*>(key_ + capacity_);
}
}
template <typename T>
Row<T>::~Row()
{
if (has_memory_)
{
free(memory_);
}
}
template <typename T>
int Row<T>::Add(integer_t key, void* delta)
{
return Add(key, *(reinterpret_cast<T*>(delta)));
}
template <typename T>
int Row<T>::Add(integer_t key, T delta)
{
if (format_ == Format::Dense)
{
if (key < 0 || key >= capacity_)
{
return -1;
}
if (fabs(static_cast<double>(value_[key])) < kEPS)
{
++nonzero_size_;
}
value_[key] += delta;
if (fabs(static_cast<double>(value_[key])) < kEPS)
{
--nonzero_size_;
}
}
else // format_ == Format::SPARSE
{
if (key < 0)
{
return -1;
}
integer_t internal_key = key + 1;
integer_t bucket;
if (FindPosition(internal_key, bucket))
{
value_[bucket] += delta;
if (fabs(static_cast<double>(value_[bucket])) < kEPS)
{
// need to delete
key_[bucket] = kDeletedKey;
--nonzero_size_;
++num_deleted_key_; // consider rehash when deleted much
if (num_deleted_key_ * 10 > capacity_)
{
Rehash();
}
}
}
else // not found, then insert
{
key_[bucket] = internal_key;
value_[bucket] = delta;
++nonzero_size_;
if (nonzero_size_ * 2 > capacity_)
{
Rehash(true); // double size of hash table
}
}
}
return 0;
}
template <typename T>
int Row<T>::Add(void *delta)
{
if (format_ == Format::Dense)
{
T *buffer = static_cast<T*>(delta);
nonzero_size_ = 0;
for (int key = 0; key < capacity_; ++key)
{
value_[key] += buffer[key];
if (fabs(static_cast<double>(value_[key])) > kEPS)
{
++nonzero_size_;
}
}
return 0;
}
else
{
return -1;
}
}
template <typename T>
void Row<T>::At(integer_t key, void* value)
{
*(reinterpret_cast<T*>(value)) = At(key);
}
template <typename T>
T Row<T>::At(integer_t key)
{
if (format_ == Format::Dense)
{
// assert(key >= 0 && key < capacity)
return value_[key];
}
else // format_ == Format::SPARSE
{
integer_t internal_key = key + 1, bucket;
if (FindPosition(internal_key, bucket))
{
return value_[bucket];
}
else
{
return 0;
}
}
}
template <typename T>
integer_t Row<T>::Capacity()
{
return capacity_;
}
template <typename T>
integer_t Row<T>::NonzeroSize()
{
return nonzero_size_;
}
template <typename T>
void Row<T>::Clear()
{
num_deleted_key_ = 0;
nonzero_size_ = 0;
memset(memory_, 0, format_ == Format::Dense ?
capacity_ * sizeof(T) : capacity_ * (sizeof(integer_t)+sizeof(T)));
}
template <typename T>
integer_t Row<T>::RowId()
{
return row_id_;
}
template <typename T>
Format Row<T>::RowFormat()
{
return format_;
}
template <typename T>
typename RowBase::iterator* Row<T>::BaseIterator()
{
RowBase::iterator* iter = new RowIterator<T>(*this);
return iter;
}
template <typename T>
RowIterator<T> Row<T>::Iterator()
{
RowIterator<T> iter(*this);
return iter;
}
template <typename T>
void Row<T>::Serialize(void* byte)
{
// Format: n, col1, col2, ... col_n, val1, val2, ..., valn
char* data = static_cast<char*>(byte);
memcpy(data, &nonzero_size_, sizeof(integer_t));
integer_t* col =
reinterpret_cast<integer_t*>(
data + sizeof(integer_t));
T* val = reinterpret_cast<T*>(
data + sizeof(integer_t)* (nonzero_size_ + 1));
iterator iter = Iterator();
for (integer_t i = 0; iter.HasNext(); ++i)
{
col[i] = iter.Key();
val[i] = iter.Value();
iter.Next();
}
}
template <typename T>
void Row<T>::BatchAdd(void* byte)
{
integer_t size;
memcpy(&size, byte, sizeof(integer_t));
char* data = static_cast<char*>(byte);
integer_t* col = reinterpret_cast<integer_t*>(data + sizeof(integer_t));
T* val = reinterpret_cast<T*>(data + sizeof(integer_t)* (size + 1));
for (integer_t i = 0; i < size; ++i)
{
Add(col[i], val[i]);
}
}
template <typename T>
std::string Row<T>::ToString()
{
std::string result = "";
if (nonzero_size_ == 0)
{
return result;
}
result += std::to_string(row_id_);
iterator iter = Iterator();
for (integer_t i = 0; iter.HasNext(); ++i)
{
result += " " + std::to_string(iter.Key()) +
":" + std::to_string(iter.Value());
iter.Next();
}
return result;
}
template <typename T>
bool Row<T>::FindPosition(const integer_t key, int& bucket)
{
bool found = false; bucket = -1; // REMARK: found never used, to be reviewed and fixed
integer_t probes = 0;
integer_t index = key % capacity_; // hash function
while (true)
{
if (key_[index] == key)
{
bucket = index;
return true; // found request key, return position of key
}
else if(key_[index] == kEmptyKey)
{
if (bucket == -1)
{
bucket = index;
}
return false; // not found, return bucket is position to insert
}
else if (key_[index] == kDeletedKey)
{
if (bucket == -1)
{
bucket = index; // keep searching, but mark record this
}
}
++probes;
index = (index + 1) % capacity_; // liear probe
assert(probes <= capacity_);
}
}
template <typename T>
void Row<T>::Rehash(bool resize)
{
if (format_ == Format::Dense)
{
return;
}
if (resize) // resize to double memory
{
void* new_memory = malloc(
capacity_ * 2 * (sizeof(integer_t)+sizeof(T)));
Row<T> new_row(row_id_, Format::Sparse, capacity_ * 2, new_memory);
for (integer_t i = 0; i < capacity_; ++i)
{
if (key_[i] > 0)
{
new_row.Add(key_[i] - 1, value_[i]);
}
}
if (has_memory_)
{
free(memory_);
}
memory_ = new_memory;
capacity_ <<= 1;
has_memory_ = true;
key_ = reinterpret_cast<integer_t*>(memory_);
value_ = reinterpret_cast<T*>(key_ + capacity_);
num_deleted_key_ = 0;
}
else // rehash in place
{
integer_t i = 0;
while (i < capacity_)
{
if (key_[i] > 0) // key need to do rehash
{
// do rehash
integer_t index = key_[i] % capacity_;
while (key_[index] < -1)
{
index = (index + 1) % capacity_;
}
key_[i] = (-key_[i] - 1);
std::swap(key_[index], key_[i]);
std::swap(value_[index], value_[i]);
}
else
{
++i;
}
}
for (integer_t i = 0; i < capacity_; ++i)
{
assert(key_[i] <= 0);
if (key_[i] < -1)
{
key_[i] = (-key_[i] - 1); // reverse key
}
if (key_[i] == kDeletedKey)
{
key_[i] = kEmptyKey;
}
}
num_deleted_key_ = 0;
}
}
// explicity instantialize template class Row
template class Row<int>;
template class Row<int64_t>;
template class Row<float>;
template class Row<double>;
//-- Row factory definition ----------------------------------------------/
RowFactoryBase *RowFactoryBase::CreateRowFactory(Type type)
{
switch (type)
{
case Type::Int: return new RowFactory<int>();
case Type::LongLong: return new RowFactory<int64_t>();
case Type::Float: return new RowFactory<float>();
case Type::Double: return new RowFactory<double>();
default: return nullptr;
}
}
template <typename T>
RowBase *RowFactory<T>::CreateRow(integer_t row_id, Format format,
integer_t capacity, void *memory)
{
return new Row<T>(row_id, format, capacity, memory);
}
}

Просмотреть файл

@ -1,78 +0,0 @@
#include "row_iter.h"
#include "row.h"
#include <cstdint>
#include <cmath>
namespace multiverso
{
template <typename T>
RowIterator<T>::RowIterator(Row<T>& row)
: row_(row), index_(0)
{
SkipInvalidValue();
}
template <typename T>
RowIterator<T>::~RowIterator() {}
template <typename T>
bool RowIterator<T>::HasNext()
{
return index_ < row_.Capacity();
}
template <typename T>
void RowIterator<T>::Next()
{
++index_;
SkipInvalidValue();
}
template <typename T>
integer_t RowIterator<T>::Key()
{
return row_.RowFormat() == Format::Dense ?
index_ : row_.key_[index_] - 1;
}
template <typename T>
void RowIterator<T>::Value(void* value)
{
T return_value = Value();
*(reinterpret_cast<T*>(value)) = return_value;
}
template <typename T>
T RowIterator<T>::Value()
{
return row_.value_[index_];
}
template <typename T>
void RowIterator<T>::SkipInvalidValue()
{
if (row_.RowFormat() == Format::Dense)
{
while (index_ < row_.Capacity() && // skip zero
fabs(static_cast<double>(row_.value_[index_])) < kEPS)
{
++index_;
}
}
else // row.RowFormat() == Format::SPARSE
{
while (index_ < row_.Capacity() &&
row_.key_[index_] <= 0) // skip empty key or deleted key
{
++index_;
}
}
}
// template class explicit instantiation
template class RowIterator<int>;
template class RowIterator<int64_t>;
template class RowIterator<float>;
template class RowIterator<double>;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше