mirror of
https://github.com/wassname/ray.git
synced 2026-09-10 12:38:43 +08:00
Rename photon -> local scheduler. (#322)
This commit is contained in:
committed by
Philipp Moritz
parent
a30eed452e
commit
1ae7e7d29e
@@ -36,7 +36,7 @@ function(define_test test_name library)
|
||||
add_executable(${test_name} test/${test_name}.c ${ARGN})
|
||||
add_dependencies(${test_name} hiredis flatcc)
|
||||
target_link_libraries(${test_name} common ${FLATBUFFERS_STATIC_LIB} ${library})
|
||||
target_compile_options(${test_name} PUBLIC "-DPLASMA_TEST -DPHOTON_TEST -DCOMMON_TEST -DRAY_COMMON_LOG_LEVEL=4 -DRAY_TIMEOUT=50")
|
||||
target_compile_options(${test_name} PUBLIC "-DPLASMA_TEST -DLOCAL_SCHEDULER_TEST -DCOMMON_TEST -DRAY_COMMON_LOG_LEVEL=4 -DRAY_TIMEOUT=50")
|
||||
endfunction()
|
||||
|
||||
define_test(common_tests "")
|
||||
|
||||
@@ -83,7 +83,7 @@ PyObject *PyObjectID_make(ObjectID object_id) {
|
||||
*
|
||||
* This is called from Python like
|
||||
*
|
||||
* task = photon.task_from_string("...")
|
||||
* task = local_scheduler.task_from_string("...")
|
||||
*
|
||||
* @param task_string String representation of the task specification.
|
||||
* @return Python task specification object.
|
||||
@@ -112,7 +112,7 @@ PyObject *PyTask_from_string(PyObject *self, PyObject *args) {
|
||||
*
|
||||
* This is called from Python like
|
||||
*
|
||||
* s = photon.task_to_string(task)
|
||||
* s = local_scheduler.task_to_string(task)
|
||||
*
|
||||
* @param task Ray task specification Python object.
|
||||
* @return String representing the task specification.
|
||||
|
||||
@@ -83,17 +83,21 @@ void GlobalSchedulerState_free(GlobalSchedulerState *state) {
|
||||
db_disconnect(state->db);
|
||||
utarray_free(state->local_schedulers);
|
||||
GlobalSchedulerPolicyState_free(state->policy_state);
|
||||
/* Delete the plasma to photon association map. */
|
||||
HASH_ITER(plasma_photon_hh, state->plasma_photon_map, entry, tmp) {
|
||||
HASH_DELETE(plasma_photon_hh, state->plasma_photon_map, entry);
|
||||
/* The hash entry is shared with the photon_plasma hashmap and will be freed
|
||||
* there. */
|
||||
/* Delete the plasma to local scheduler association map. */
|
||||
HASH_ITER(plasma_local_scheduler_hh, state->plasma_local_scheduler_map, entry,
|
||||
tmp) {
|
||||
HASH_DELETE(plasma_local_scheduler_hh, state->plasma_local_scheduler_map,
|
||||
entry);
|
||||
/* The hash entry is shared with the local_scheduler_plasma hashmap and will
|
||||
* be freed there. */
|
||||
free(entry->aux_address);
|
||||
}
|
||||
|
||||
/* Delete the photon to plasma association map. */
|
||||
HASH_ITER(photon_plasma_hh, state->photon_plasma_map, entry, tmp) {
|
||||
HASH_DELETE(photon_plasma_hh, state->photon_plasma_map, entry);
|
||||
/* Delete the local scheduler to plasma association map. */
|
||||
HASH_ITER(local_scheduler_plasma_hh, state->local_scheduler_plasma_map, entry,
|
||||
tmp) {
|
||||
HASH_DELETE(local_scheduler_plasma_hh, state->local_scheduler_plasma_map,
|
||||
entry);
|
||||
/* Now free the shared hash entry -- no longer needed. */
|
||||
free(entry);
|
||||
}
|
||||
@@ -135,13 +139,13 @@ void signal_handler(int signal) {
|
||||
/* End of the cleanup code. */
|
||||
|
||||
LocalScheduler *get_local_scheduler(GlobalSchedulerState *state,
|
||||
DBClientID photon_id) {
|
||||
DBClientID local_scheduler_id) {
|
||||
LocalScheduler *local_scheduler_ptr;
|
||||
for (int i = 0; i < utarray_len(state->local_schedulers); ++i) {
|
||||
local_scheduler_ptr =
|
||||
(LocalScheduler *) utarray_eltptr(state->local_schedulers, i);
|
||||
if (DBClientID_equal(local_scheduler_ptr->id, photon_id)) {
|
||||
LOG_DEBUG("photon_id matched cached local scheduler entry.");
|
||||
if (DBClientID_equal(local_scheduler_ptr->id, local_scheduler_id)) {
|
||||
LOG_DEBUG("local_scheduler_id matched cached local scheduler entry.");
|
||||
return local_scheduler_ptr;
|
||||
}
|
||||
}
|
||||
@@ -176,32 +180,36 @@ void process_new_db_client(DBClientID db_client_id,
|
||||
LOG_DEBUG("db client table callback for db client = %s",
|
||||
ObjectID_to_string(db_client_id, id_string, ID_STRING_SIZE));
|
||||
UNUSED(id_string);
|
||||
if (strncmp(client_type, "photon", strlen("photon")) == 0) {
|
||||
/* Add plasma_manager ip:port -> photon_db_client_id association to state.
|
||||
*/
|
||||
AuxAddressEntry *plasma_photon_entry = calloc(1, sizeof(AuxAddressEntry));
|
||||
plasma_photon_entry->aux_address = strdup(aux_address);
|
||||
plasma_photon_entry->photon_db_client_id = db_client_id;
|
||||
HASH_ADD_KEYPTR(plasma_photon_hh, state->plasma_photon_map,
|
||||
plasma_photon_entry->aux_address,
|
||||
strlen(plasma_photon_entry->aux_address),
|
||||
plasma_photon_entry);
|
||||
if (strncmp(client_type, "local_scheduler", strlen("local_scheduler")) == 0) {
|
||||
/* Add plasma_manager ip:port -> local_scheduler_db_client_id association to
|
||||
* state. */
|
||||
AuxAddressEntry *plasma_local_scheduler_entry =
|
||||
calloc(1, sizeof(AuxAddressEntry));
|
||||
plasma_local_scheduler_entry->aux_address = strdup(aux_address);
|
||||
plasma_local_scheduler_entry->local_scheduler_db_client_id = db_client_id;
|
||||
HASH_ADD_KEYPTR(plasma_local_scheduler_hh,
|
||||
state->plasma_local_scheduler_map,
|
||||
plasma_local_scheduler_entry->aux_address,
|
||||
strlen(plasma_local_scheduler_entry->aux_address),
|
||||
plasma_local_scheduler_entry);
|
||||
|
||||
/* Add photon_db_client_id -> plasma_manager ip:port association to state.
|
||||
*/
|
||||
HASH_ADD(photon_plasma_hh, state->photon_plasma_map, photon_db_client_id,
|
||||
sizeof(plasma_photon_entry->photon_db_client_id),
|
||||
plasma_photon_entry);
|
||||
/* Add local_scheduler_db_client_id -> plasma_manager ip:port association to
|
||||
* state. */
|
||||
HASH_ADD(local_scheduler_plasma_hh, state->local_scheduler_plasma_map,
|
||||
local_scheduler_db_client_id,
|
||||
sizeof(plasma_local_scheduler_entry->local_scheduler_db_client_id),
|
||||
plasma_local_scheduler_entry);
|
||||
|
||||
#if (RAY_COMMON_LOG_LEVEL <= RAY_COMMON_DEBUG)
|
||||
{
|
||||
/* Print the photon to plasma association map so far. */
|
||||
/* Print the local scheduler to plasma association map so far. */
|
||||
AuxAddressEntry *entry, *tmp;
|
||||
LOG_DEBUG("Photon to Plasma hash map so far:");
|
||||
HASH_ITER(plasma_photon_hh, state->plasma_photon_map, entry, tmp) {
|
||||
LOG_DEBUG("Local scheduler to plasma hash map so far:");
|
||||
HASH_ITER(plasma_local_scheduler_hh, state->plasma_local_scheduler_map,
|
||||
entry, tmp) {
|
||||
LOG_DEBUG("%s -> %s", entry->aux_address,
|
||||
ObjectID_to_string(entry->photon_db_client_id, id_string,
|
||||
ID_STRING_SIZE));
|
||||
ObjectID_to_string(entry->local_scheduler_db_client_id,
|
||||
id_string, ID_STRING_SIZE));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,17 +44,17 @@ typedef struct {
|
||||
} SchedulerObjectInfo;
|
||||
|
||||
/**
|
||||
* A struct used for caching Photon to Plasma association.
|
||||
* A struct used for caching local scheduler to Plasma association.
|
||||
*/
|
||||
typedef struct {
|
||||
/** IP:port string for the plasma_manager. */
|
||||
char *aux_address;
|
||||
/** Photon db client id. */
|
||||
DBClientID photon_db_client_id;
|
||||
/** Plasma_manager ip:port -> photon_db_client_id. */
|
||||
UT_hash_handle plasma_photon_hh;
|
||||
/** Photon_db_client_id -> plasma_manager ip:port. */
|
||||
UT_hash_handle photon_plasma_hh;
|
||||
/** Local scheduler db client id. */
|
||||
DBClientID local_scheduler_db_client_id;
|
||||
/** Plasma_manager ip:port -> local_scheduler_db_client_id. */
|
||||
UT_hash_handle plasma_local_scheduler_hh;
|
||||
/** local_scheduler_db_client_id -> plasma_manager ip:port. */
|
||||
UT_hash_handle local_scheduler_plasma_hh;
|
||||
} AuxAddressEntry;
|
||||
|
||||
/**
|
||||
@@ -71,10 +71,10 @@ typedef struct {
|
||||
UT_array *local_schedulers;
|
||||
/** The state managed by the scheduling policy. */
|
||||
GlobalSchedulerPolicyState *policy_state;
|
||||
/** The plasma_manager ip:port -> photon_db_client_id association. */
|
||||
AuxAddressEntry *plasma_photon_map;
|
||||
/** The photon_db_client_id -> plasma_manager ip:port association. */
|
||||
AuxAddressEntry *photon_plasma_map;
|
||||
/** The plasma_manager ip:port -> local_scheduler_db_client_id association. */
|
||||
AuxAddressEntry *plasma_local_scheduler_map;
|
||||
/** The local_scheduler_db_client_id -> plasma_manager ip:port association. */
|
||||
AuxAddressEntry *local_scheduler_plasma_map;
|
||||
/** Objects cached by this global scheduler instance. */
|
||||
SchedulerObjectInfo *scheduler_object_info_table;
|
||||
/** An array of tasks that haven't been scheduled yet. */
|
||||
@@ -83,15 +83,15 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* This is a helper method to look up the local scheduler struct that
|
||||
* corresponds to a particular photon_id.
|
||||
* corresponds to a particular local_scheduler_id.
|
||||
*
|
||||
* @param state The state of the global scheduler.
|
||||
* @param The photon_id of the local scheduler.
|
||||
* @param The local_scheduler_id of the local scheduler.
|
||||
* @return The corresponding local scheduler struct. If the global scheduler is
|
||||
* not aware of the local scheduler, then this will be NULL.
|
||||
*/
|
||||
LocalScheduler *get_local_scheduler(GlobalSchedulerState *state,
|
||||
DBClientID photon_id);
|
||||
DBClientID local_scheduler_id);
|
||||
|
||||
/**
|
||||
* Assign the given task to the local scheduler, update Redis and scheduler data
|
||||
|
||||
@@ -154,42 +154,48 @@ void free_object_size_hashmap(ObjectSizeEntry *object_size_table) {
|
||||
}
|
||||
}
|
||||
|
||||
DBClientID get_photon_id(GlobalSchedulerState *state,
|
||||
const char *plasma_location) {
|
||||
DBClientID get_local_scheduler_id(GlobalSchedulerState *state,
|
||||
const char *plasma_location) {
|
||||
AuxAddressEntry *aux_entry = NULL;
|
||||
DBClientID photon_id = NIL_ID;
|
||||
DBClientID local_scheduler_id = NIL_ID;
|
||||
if (plasma_location != NULL) {
|
||||
LOG_DEBUG("max object size location found : %s", plasma_location);
|
||||
/* Lookup association of plasma location to photon. */
|
||||
HASH_FIND(plasma_photon_hh, state->plasma_photon_map, plasma_location,
|
||||
uthash_strlen(plasma_location), aux_entry);
|
||||
/* Lookup association of plasma location to local scheduler. */
|
||||
HASH_FIND(plasma_local_scheduler_hh, state->plasma_local_scheduler_map,
|
||||
plasma_location, uthash_strlen(plasma_location), aux_entry);
|
||||
if (aux_entry) {
|
||||
LOG_DEBUG("found photon db client association for plasma ip:port = %s",
|
||||
aux_entry->aux_address);
|
||||
/* Plasma to photon db client ID association found, get photon ID. */
|
||||
photon_id = aux_entry->photon_db_client_id;
|
||||
LOG_DEBUG(
|
||||
"found local scheduler db client association for plasma ip:port = %s",
|
||||
aux_entry->aux_address);
|
||||
/* Plasma to local scheduler db client ID association found, get local
|
||||
* scheduler ID. */
|
||||
local_scheduler_id = aux_entry->local_scheduler_db_client_id;
|
||||
} else {
|
||||
LOG_ERROR("photon db client association not found for plasma ip:port=%s",
|
||||
plasma_location);
|
||||
LOG_ERROR(
|
||||
"local scheduler db client association not found for plasma "
|
||||
"ip:port=%s",
|
||||
plasma_location);
|
||||
}
|
||||
}
|
||||
|
||||
char id_string[ID_STRING_SIZE];
|
||||
LOG_DEBUG("photon ID found = %s",
|
||||
ObjectID_to_string(photon_id, id_string, ID_STRING_SIZE));
|
||||
LOG_DEBUG("local scheduler ID found = %s",
|
||||
ObjectID_to_string(local_scheduler_id, id_string, ID_STRING_SIZE));
|
||||
UNUSED(id_string);
|
||||
|
||||
if (IS_NIL_ID(photon_id)) {
|
||||
return photon_id;
|
||||
if (IS_NIL_ID(local_scheduler_id)) {
|
||||
return local_scheduler_id;
|
||||
}
|
||||
|
||||
/* Check to make sure this photon_db_client_id matches one of the
|
||||
/* Check to make sure this local_scheduler_db_client_id matches one of the
|
||||
* schedulers. */
|
||||
LocalScheduler *local_scheduler_ptr = get_local_scheduler(state, photon_id);
|
||||
LocalScheduler *local_scheduler_ptr =
|
||||
get_local_scheduler(state, local_scheduler_id);
|
||||
if (local_scheduler_ptr == NULL) {
|
||||
LOG_WARN("photon_id didn't match any cached local scheduler entries");
|
||||
LOG_WARN(
|
||||
"local_scheduler_id didn't match any cached local scheduler entries");
|
||||
}
|
||||
return photon_id;
|
||||
return local_scheduler_id;
|
||||
}
|
||||
|
||||
double inner_product(double a[], double b[], int size) {
|
||||
@@ -210,22 +216,25 @@ double calculate_object_size_fraction(GlobalSchedulerState *state,
|
||||
double object_size_fraction = 0;
|
||||
if (total_task_object_size > 0) {
|
||||
/* Does this node contribute anything to this task object size? */
|
||||
/* Lookup scheduler->id in photon_plasma_map to get plasma aux address,
|
||||
* which is used as the key for object_size_table.
|
||||
* This uses the plasma aux address to locate the object_size this node
|
||||
* contributes. */
|
||||
AuxAddressEntry *photon_plasma_pair = NULL;
|
||||
HASH_FIND(photon_plasma_hh, state->photon_plasma_map, &(scheduler->id),
|
||||
sizeof(scheduler->id), photon_plasma_pair);
|
||||
if (photon_plasma_pair != NULL) {
|
||||
/* Lookup scheduler->id in local_scheduler_plasma_map to get plasma aux
|
||||
* address, which is used as the key for object_size_table. This uses the
|
||||
* plasma aux address to locate the object_size this node contributes. */
|
||||
AuxAddressEntry *local_scheduler_plasma_pair = NULL;
|
||||
HASH_FIND(local_scheduler_plasma_hh, state->local_scheduler_plasma_map,
|
||||
&(scheduler->id), sizeof(scheduler->id),
|
||||
local_scheduler_plasma_pair);
|
||||
if (local_scheduler_plasma_pair != NULL) {
|
||||
ObjectSizeEntry *s = NULL;
|
||||
/* Found this node's photon to plasma mapping. Use the corresponding
|
||||
* plasma key to see if this node has any cached objects for this task. */
|
||||
HASH_FIND_STR(object_size_table, photon_plasma_pair->aux_address, s);
|
||||
/* Found this node's local scheduler to plasma mapping. Use the
|
||||
* corresponding plasma key to see if this node has any cached objects for
|
||||
* this task. */
|
||||
HASH_FIND_STR(object_size_table, local_scheduler_plasma_pair->aux_address,
|
||||
s);
|
||||
if (s != NULL) {
|
||||
/* This node has some of this task's objects. Calculate what fraction.
|
||||
*/
|
||||
CHECK(strcmp(s->object_location, photon_plasma_pair->aux_address) == 0);
|
||||
CHECK(strcmp(s->object_location,
|
||||
local_scheduler_plasma_pair->aux_address) == 0);
|
||||
object_size_fraction =
|
||||
MIN(1, (double) (s->total_object_size) / total_task_object_size);
|
||||
}
|
||||
@@ -286,9 +295,10 @@ bool handle_task_waiting(GlobalSchedulerState *state,
|
||||
|
||||
/* Go through all the nodes, calculate the score for each, pick max score. */
|
||||
LocalScheduler *scheduler = NULL;
|
||||
double best_photon_score = INT32_MIN;
|
||||
CHECKM(best_photon_score < 0, "We might have a floating point underflow");
|
||||
DBClientID best_photon_id = NIL_ID; /* best node to send this task */
|
||||
double best_local_scheduler_score = INT32_MIN;
|
||||
CHECKM(best_local_scheduler_score < 0,
|
||||
"We might have a floating point underflow");
|
||||
DBClientID best_local_scheduler_id = NIL_ID; /* best node to send this task */
|
||||
for (scheduler = (LocalScheduler *) utarray_front(state->local_schedulers);
|
||||
scheduler != NULL; scheduler = (LocalScheduler *) utarray_next(
|
||||
state->local_schedulers, scheduler)) {
|
||||
@@ -300,9 +310,9 @@ bool handle_task_waiting(GlobalSchedulerState *state,
|
||||
task_feasible = true;
|
||||
/* This node satisfies the hard capacity constraint. Calculate its score. */
|
||||
double score = -1 * calculate_cost_pending(state, scheduler);
|
||||
if (score > best_photon_score) {
|
||||
best_photon_score = score;
|
||||
best_photon_id = scheduler->id;
|
||||
if (score > best_local_scheduler_score) {
|
||||
best_local_scheduler_score = score;
|
||||
best_local_scheduler_id = scheduler->id;
|
||||
}
|
||||
} /* For each local scheduler. */
|
||||
|
||||
@@ -317,10 +327,10 @@ bool handle_task_waiting(GlobalSchedulerState *state,
|
||||
* cache the task in case new local schedulers satisfy it in the future. */
|
||||
return false;
|
||||
}
|
||||
CHECKM(!IS_NIL_ID(best_photon_id),
|
||||
CHECKM(!IS_NIL_ID(best_local_scheduler_id),
|
||||
"Task is feasible, but doesn't have a local scheduler assigned.");
|
||||
/* A local scheduler ID was found, so assign the task. */
|
||||
assign_task_to_local_scheduler(state, task, best_photon_id);
|
||||
assign_task_to_local_scheduler(state, task, best_local_scheduler_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(local_scheduler)
|
||||
|
||||
# Recursively include common
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../common/cmake/Common.cmake)
|
||||
|
||||
if(APPLE)
|
||||
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
|
||||
endif(APPLE)
|
||||
|
||||
include_directories("${PYTHON_INCLUDE_DIRS}")
|
||||
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} --std=c99 -Werror")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
link_libraries(rt)
|
||||
endif()
|
||||
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/")
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../")
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../plasma/")
|
||||
|
||||
add_library(local_scheduler_library SHARED
|
||||
local_scheduler_extension.c
|
||||
../common/lib/python/common_extension.c)
|
||||
|
||||
get_filename_component(PYTHON_SHARED_LIBRARY ${PYTHON_LIBRARIES} NAME)
|
||||
if(APPLE)
|
||||
add_custom_command(TARGET local_scheduler_library
|
||||
POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change ${PYTHON_SHARED_LIBRARY} ${PYTHON_LIBRARIES} liblocal_scheduler_library.so)
|
||||
endif(APPLE)
|
||||
|
||||
add_library(local_scheduler_client STATIC local_scheduler_client.c)
|
||||
|
||||
target_link_libraries(local_scheduler_library local_scheduler_client ${COMMON_LIB} ${PYTHON_LIBRARIES})
|
||||
|
||||
add_executable(local_scheduler local_scheduler.c local_scheduler_algorithm.c)
|
||||
target_link_libraries(local_scheduler local_scheduler_client common ${HIREDIS_LIB} plasma_lib)
|
||||
|
||||
add_executable(local_scheduler_tests test/local_scheduler_tests.c local_scheduler.c local_scheduler_algorithm.c )
|
||||
target_link_libraries(local_scheduler_tests local_scheduler_client common ${HIREDIS_LIB} plasma_lib)
|
||||
target_compile_options(local_scheduler_tests PUBLIC "-DLOCAL_SCHEDULER_TEST")
|
||||
|
||||
install(TARGETS local_scheduler_library DESTINATION ${CMAKE_SOURCE_DIR}/local_scheduler)
|
||||
@@ -12,9 +12,9 @@
|
||||
#include "io.h"
|
||||
#include "logging.h"
|
||||
#include "object_info.h"
|
||||
#include "photon.h"
|
||||
#include "photon_scheduler.h"
|
||||
#include "photon_algorithm.h"
|
||||
#include "local_scheduler_shared.h"
|
||||
#include "local_scheduler.h"
|
||||
#include "local_scheduler_algorithm.h"
|
||||
#include "state/actor_notification_table.h"
|
||||
#include "state/db.h"
|
||||
#include "state/task_table.h"
|
||||
@@ -361,8 +361,8 @@ LocalSchedulerState *LocalSchedulerState_init(
|
||||
db_connect_args[4] = "num_gpus";
|
||||
db_connect_args[5] = utstring_body(num_gpus);
|
||||
}
|
||||
state->db = db_connect(redis_addr, redis_port, "photon", node_ip_address,
|
||||
num_args, db_connect_args);
|
||||
state->db = db_connect(redis_addr, redis_port, "local_scheduler",
|
||||
node_ip_address, num_args, db_connect_args);
|
||||
utstring_free(num_cpus);
|
||||
utstring_free(num_gpus);
|
||||
free(db_connect_args);
|
||||
@@ -417,7 +417,7 @@ void update_dynamic_resources(LocalSchedulerState *state,
|
||||
|
||||
if (!return_resources && state->dynamic_resources[i] < 0) {
|
||||
/* We are using more resources than we have been allocated. */
|
||||
LOG_WARN("photon dynamic resources dropped to %8.4f\t%8.4f\n",
|
||||
LOG_WARN("local_scheduler dynamic resources dropped to %8.4f\t%8.4f\n",
|
||||
state->dynamic_resources[0], state->dynamic_resources[1]);
|
||||
}
|
||||
CHECK(state->dynamic_resources[i] <= state->static_resources[i]);
|
||||
@@ -911,7 +911,7 @@ void start_server(const char *node_ip_address,
|
||||
|
||||
/* Only declare the main function if we are not in testing mode, since the test
|
||||
* suite has its own declaration of main. */
|
||||
#ifndef PHOTON_TEST
|
||||
#ifndef LOCAL_SCHEDULER_TEST
|
||||
int main(int argc, char *argv[]) {
|
||||
signal(SIGTERM, signal_handler);
|
||||
/* Path of the listening socket of the local scheduler. */
|
||||
@@ -922,7 +922,8 @@ int main(int argc, char *argv[]) {
|
||||
char *plasma_store_socket_name = NULL;
|
||||
/* Socket name for the local Plasma manager. */
|
||||
char *plasma_manager_socket_name = NULL;
|
||||
/* Address for the plasma manager associated with this Photon instance. */
|
||||
/* Address for the plasma manager associated with this local scheduler
|
||||
* instance. */
|
||||
char *plasma_manager_address = NULL;
|
||||
/* The IP address of the node that this local scheduler is running on. */
|
||||
char *node_ip_address = NULL;
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PHOTON_SCHEDULER_H
|
||||
#define PHOTON_SCHEDULER_H
|
||||
#ifndef LOCAL_SCHEDULER_H
|
||||
#define LOCAL_SCHEDULER_H
|
||||
|
||||
#include "task.h"
|
||||
#include "event_loop.h"
|
||||
@@ -110,7 +110,7 @@ void update_dynamic_resources(LocalSchedulerState *state,
|
||||
bool return_resources);
|
||||
|
||||
/** The following methods are for testing purposes only. */
|
||||
#ifdef PHOTON_TEST
|
||||
#ifdef LOCAL_SCHEDULER_TEST
|
||||
LocalSchedulerState *LocalSchedulerState_init(
|
||||
const char *node_ip_address,
|
||||
event_loop *loop,
|
||||
@@ -136,4 +136,4 @@ void process_message(event_loop *loop,
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* PHOTON_SCHEDULER_H */
|
||||
#endif /* LOCAL_SCHEDULER_H */
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "photon_algorithm.h"
|
||||
#include "local_scheduler_algorithm.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "utarray.h"
|
||||
@@ -7,8 +7,8 @@
|
||||
#include "state/task_table.h"
|
||||
#include "state/local_scheduler_table.h"
|
||||
#include "state/object_table.h"
|
||||
#include "photon.h"
|
||||
#include "photon_scheduler.h"
|
||||
#include "local_scheduler_shared.h"
|
||||
#include "local_scheduler.h"
|
||||
#include "common/task.h"
|
||||
|
||||
/* Declared for convenience. */
|
||||
@@ -65,7 +65,8 @@ typedef struct {
|
||||
UT_hash_handle hh;
|
||||
} LocalActorInfo;
|
||||
|
||||
/** Part of the photon state that is maintained by the scheduling algorithm. */
|
||||
/** Part of the local scheduler state that is maintained by the scheduling
|
||||
* algorithm. */
|
||||
struct SchedulingAlgorithmState {
|
||||
/** An array of pointers to tasks that are waiting for dependencies. */
|
||||
task_queue_entry *waiting_task_queue;
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef PHOTON_ALGORITHM_H
|
||||
#define PHOTON_ALGORITHM_H
|
||||
#ifndef LOCAL_SCHEDULER_ALGORITHM_H
|
||||
#define LOCAL_SCHEDULER_ALGORITHM_H
|
||||
|
||||
#include "photon.h"
|
||||
#include "local_scheduler_shared.h"
|
||||
#include "common/task.h"
|
||||
#include "state/local_scheduler_table.h"
|
||||
|
||||
@@ -250,7 +250,7 @@ void print_worker_info(const char *message,
|
||||
SchedulingAlgorithmState *algorithm_state);
|
||||
|
||||
/** The following methods are for testing purposes only. */
|
||||
#ifdef PHOTON_TEST
|
||||
#ifdef LOCAL_SCHEDULER_TEST
|
||||
/**
|
||||
* Get the number of tasks currently waiting for object dependencies to become
|
||||
* available locally.
|
||||
@@ -269,4 +269,4 @@ int num_waiting_tasks(SchedulingAlgorithmState *algorithm_state);
|
||||
int num_dispatch_tasks(SchedulingAlgorithmState *algorithm_state);
|
||||
#endif
|
||||
|
||||
#endif /* PHOTON_ALGORITHM_H */
|
||||
#endif /* LOCAL_SCHEDULER_ALGORITHM_H */
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "photon_client.h"
|
||||
#include "local_scheduler_client.h"
|
||||
|
||||
#include "common/io.h"
|
||||
#include "common/task.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
PhotonConnection *PhotonConnection_init(const char *photon_socket,
|
||||
ActorID actor_id) {
|
||||
PhotonConnection *result =
|
||||
(PhotonConnection *) malloc(sizeof(PhotonConnection));
|
||||
result->conn = connect_ipc_sock_retry(photon_socket, -1, -1);
|
||||
LocalSchedulerConnection *LocalSchedulerConnection_init(
|
||||
const char *local_scheduler_socket,
|
||||
ActorID actor_id) {
|
||||
LocalSchedulerConnection *result =
|
||||
(LocalSchedulerConnection *) malloc(sizeof(LocalSchedulerConnection));
|
||||
result->conn = connect_ipc_sock_retry(local_scheduler_socket, -1, -1);
|
||||
register_worker_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
/* Register the process ID with the local scheduler. */
|
||||
@@ -20,16 +21,16 @@ PhotonConnection *PhotonConnection_init(const char *photon_socket,
|
||||
return result;
|
||||
}
|
||||
|
||||
void PhotonConnection_free(PhotonConnection *conn) {
|
||||
void LocalSchedulerConnection_free(LocalSchedulerConnection *conn) {
|
||||
close(conn->conn);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
void photon_log_event(PhotonConnection *conn,
|
||||
uint8_t *key,
|
||||
int64_t key_length,
|
||||
uint8_t *value,
|
||||
int64_t value_length) {
|
||||
void local_scheduler_log_event(LocalSchedulerConnection *conn,
|
||||
uint8_t *key,
|
||||
int64_t key_length,
|
||||
uint8_t *value,
|
||||
int64_t value_length) {
|
||||
int64_t message_length =
|
||||
sizeof(key_length) + sizeof(value_length) + key_length + value_length;
|
||||
uint8_t *message = (uint8_t *) malloc(message_length);
|
||||
@@ -47,12 +48,12 @@ void photon_log_event(PhotonConnection *conn,
|
||||
free(message);
|
||||
}
|
||||
|
||||
void photon_submit(PhotonConnection *conn, task_spec *task) {
|
||||
void local_scheduler_submit(LocalSchedulerConnection *conn, task_spec *task) {
|
||||
write_message(conn->conn, SUBMIT_TASK, task_spec_size(task),
|
||||
(uint8_t *) task);
|
||||
}
|
||||
|
||||
task_spec *photon_get_task(PhotonConnection *conn) {
|
||||
task_spec *local_scheduler_get_task(LocalSchedulerConnection *conn) {
|
||||
write_message(conn->conn, GET_TASK, 0, NULL);
|
||||
int64_t type;
|
||||
int64_t length;
|
||||
@@ -66,19 +67,20 @@ task_spec *photon_get_task(PhotonConnection *conn) {
|
||||
return task;
|
||||
}
|
||||
|
||||
void photon_task_done(PhotonConnection *conn) {
|
||||
void local_scheduler_task_done(LocalSchedulerConnection *conn) {
|
||||
write_message(conn->conn, TASK_DONE, 0, NULL);
|
||||
}
|
||||
|
||||
void photon_reconstruct_object(PhotonConnection *conn, ObjectID object_id) {
|
||||
void local_scheduler_reconstruct_object(LocalSchedulerConnection *conn,
|
||||
ObjectID object_id) {
|
||||
write_message(conn->conn, RECONSTRUCT_OBJECT, sizeof(object_id),
|
||||
(uint8_t *) &object_id);
|
||||
}
|
||||
|
||||
void photon_log_message(PhotonConnection *conn) {
|
||||
void local_scheduler_log_message(LocalSchedulerConnection *conn) {
|
||||
write_message(conn->conn, LOG_MESSAGE, 0, NULL);
|
||||
}
|
||||
|
||||
void photon_notify_unblocked(PhotonConnection *conn) {
|
||||
void local_scheduler_notify_unblocked(LocalSchedulerConnection *conn) {
|
||||
write_message(conn->conn, NOTIFY_UNBLOCKED, 0, NULL);
|
||||
}
|
||||
@@ -1,33 +1,36 @@
|
||||
#ifndef PHOTON_CLIENT_H
|
||||
#define PHOTON_CLIENT_H
|
||||
#ifndef LOCAL_SCHEDULER_CLIENT_H
|
||||
#define LOCAL_SCHEDULER_CLIENT_H
|
||||
|
||||
#include "common/task.h"
|
||||
#include "photon.h"
|
||||
#include "local_scheduler_shared.h"
|
||||
|
||||
typedef struct {
|
||||
/* File descriptor of the Unix domain socket that connects to photon. */
|
||||
/** File descriptor of the Unix domain socket that connects to local
|
||||
* scheduler. */
|
||||
int conn;
|
||||
} PhotonConnection;
|
||||
} LocalSchedulerConnection;
|
||||
|
||||
/**
|
||||
* Connect to the local scheduler.
|
||||
*
|
||||
* @param photon_socket The name of the socket to use to connect to the local
|
||||
* scheduler.
|
||||
* @param local_scheduler_socket The name of the socket to use to connect to the
|
||||
* local scheduler.
|
||||
* @param actor_id The ID of the actor running on this worker. If no actor is
|
||||
* running on this actor, this should be NIL_ACTOR_ID.
|
||||
* @return The connection information.
|
||||
*/
|
||||
PhotonConnection *PhotonConnection_init(const char *photon_socket,
|
||||
ActorID actor_id);
|
||||
LocalSchedulerConnection *LocalSchedulerConnection_init(
|
||||
const char *local_scheduler_socket,
|
||||
ActorID actor_id);
|
||||
|
||||
/**
|
||||
* Disconnect from the local scheduler.
|
||||
*
|
||||
* @param conn Photon connection information returned by PhotonConnection_init.
|
||||
* @param conn Local scheduler connection information returned by
|
||||
* LocalSchedulerConnection_init.
|
||||
* @return Void.
|
||||
*/
|
||||
void PhotonConnection_free(PhotonConnection *conn);
|
||||
void LocalSchedulerConnection_free(LocalSchedulerConnection *conn);
|
||||
|
||||
/**
|
||||
* Submit a task to the local scheduler.
|
||||
@@ -36,7 +39,7 @@ void PhotonConnection_free(PhotonConnection *conn);
|
||||
* @param task The address of the task to submit.
|
||||
* @return Void.
|
||||
*/
|
||||
void photon_submit(PhotonConnection *conn, task_spec *task);
|
||||
void local_scheduler_submit(LocalSchedulerConnection *conn, task_spec *task);
|
||||
|
||||
/**
|
||||
* Log an event to the event log. This will call RPUSH key value. We use RPUSH
|
||||
@@ -51,11 +54,11 @@ void photon_submit(PhotonConnection *conn, task_spec *task);
|
||||
* @param value_length The length of the value.
|
||||
* @return Void.
|
||||
*/
|
||||
void photon_log_event(PhotonConnection *conn,
|
||||
uint8_t *key,
|
||||
int64_t key_length,
|
||||
uint8_t *value,
|
||||
int64_t value_length);
|
||||
void local_scheduler_log_event(LocalSchedulerConnection *conn,
|
||||
uint8_t *key,
|
||||
int64_t key_length,
|
||||
uint8_t *value,
|
||||
int64_t value_length);
|
||||
|
||||
/**
|
||||
* Get next task for this client. This will block until the scheduler assigns
|
||||
@@ -67,7 +70,7 @@ void photon_log_event(PhotonConnection *conn,
|
||||
* @param conn The connection information.
|
||||
* @return The address of the assigned task.
|
||||
*/
|
||||
task_spec *photon_get_task(PhotonConnection *conn);
|
||||
task_spec *local_scheduler_get_task(LocalSchedulerConnection *conn);
|
||||
|
||||
/**
|
||||
* Tell the local scheduler that the client has finished executing a task.
|
||||
@@ -75,7 +78,7 @@ task_spec *photon_get_task(PhotonConnection *conn);
|
||||
* @param conn The connection information.
|
||||
* @return Void.
|
||||
*/
|
||||
void photon_task_done(PhotonConnection *conn);
|
||||
void local_scheduler_task_done(LocalSchedulerConnection *conn);
|
||||
|
||||
/**
|
||||
* Tell the local scheduler to reconstruct an object.
|
||||
@@ -84,7 +87,8 @@ void photon_task_done(PhotonConnection *conn);
|
||||
* @param object_id The ID of the object to reconstruct.
|
||||
* @return Void.
|
||||
*/
|
||||
void photon_reconstruct_object(PhotonConnection *conn, ObjectID object_id);
|
||||
void local_scheduler_reconstruct_object(LocalSchedulerConnection *conn,
|
||||
ObjectID object_id);
|
||||
|
||||
/**
|
||||
* Send a log message to the local scheduler.
|
||||
@@ -92,7 +96,7 @@ void photon_reconstruct_object(PhotonConnection *conn, ObjectID object_id);
|
||||
* @param conn The connection information.
|
||||
* @return Void.
|
||||
*/
|
||||
void photon_log_message(PhotonConnection *conn);
|
||||
void local_scheduler_log_message(LocalSchedulerConnection *conn);
|
||||
|
||||
/**
|
||||
* Notify the local scheduler that this client (worker) is no longer blocked.
|
||||
@@ -100,6 +104,6 @@ void photon_log_message(PhotonConnection *conn);
|
||||
* @param conn The connection information.
|
||||
* @return Void.
|
||||
*/
|
||||
void photon_notify_unblocked(PhotonConnection *conn);
|
||||
void local_scheduler_notify_unblocked(LocalSchedulerConnection *conn);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,234 @@
|
||||
#include <Python.h>
|
||||
|
||||
#include "common_extension.h"
|
||||
#include "local_scheduler_client.h"
|
||||
#include "task.h"
|
||||
|
||||
PyObject *LocalSchedulerError;
|
||||
|
||||
// clang-format off
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
LocalSchedulerConnection *local_scheduler_connection;
|
||||
} PyLocalSchedulerClient;
|
||||
// clang-format on
|
||||
|
||||
static int PyLocalSchedulerClient_init(PyLocalSchedulerClient *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds) {
|
||||
char *socket_name;
|
||||
ActorID actor_id;
|
||||
if (!PyArg_ParseTuple(args, "sO&", &socket_name, PyStringToUniqueID,
|
||||
&actor_id)) {
|
||||
return -1;
|
||||
}
|
||||
/* Connect to the local scheduler. */
|
||||
self->local_scheduler_connection =
|
||||
LocalSchedulerConnection_init(socket_name, actor_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PyLocalSchedulerClient_dealloc(PyLocalSchedulerClient *self) {
|
||||
LocalSchedulerConnection_free(
|
||||
((PyLocalSchedulerClient *) self)->local_scheduler_connection);
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
static PyObject *PyLocalSchedulerClient_submit(PyObject *self, PyObject *args) {
|
||||
PyObject *py_task;
|
||||
if (!PyArg_ParseTuple(args, "O", &py_task)) {
|
||||
return NULL;
|
||||
}
|
||||
local_scheduler_submit(
|
||||
((PyLocalSchedulerClient *) self)->local_scheduler_connection,
|
||||
((PyTask *) py_task)->spec);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static PyObject *PyLocalSchedulerClient_get_task(PyObject *self) {
|
||||
task_spec *task_spec;
|
||||
/* Drop the global interpreter lock while we get a task because
|
||||
* local_scheduler_get_task may block for a long time. */
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
task_spec = local_scheduler_get_task(
|
||||
((PyLocalSchedulerClient *) self)->local_scheduler_connection);
|
||||
Py_END_ALLOW_THREADS
|
||||
return PyTask_make(task_spec);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static PyObject *PyLocalSchedulerClient_reconstruct_object(PyObject *self,
|
||||
PyObject *args) {
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&", PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
local_scheduler_reconstruct_object(
|
||||
((PyLocalSchedulerClient *) self)->local_scheduler_connection, object_id);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *PyLocalSchedulerClient_log_event(PyObject *self,
|
||||
PyObject *args) {
|
||||
const char *key;
|
||||
int key_length;
|
||||
const char *value;
|
||||
int value_length;
|
||||
if (!PyArg_ParseTuple(args, "s#s#", &key, &key_length, &value,
|
||||
&value_length)) {
|
||||
return NULL;
|
||||
}
|
||||
local_scheduler_log_event(
|
||||
((PyLocalSchedulerClient *) self)->local_scheduler_connection,
|
||||
(uint8_t *) key, key_length, (uint8_t *) value, value_length);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *PyLocalSchedulerClient_notify_unblocked(PyObject *self) {
|
||||
local_scheduler_notify_unblocked(
|
||||
((PyLocalSchedulerClient *) self)->local_scheduler_connection);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef PyLocalSchedulerClient_methods[] = {
|
||||
{"submit", (PyCFunction) PyLocalSchedulerClient_submit, METH_VARARGS,
|
||||
"Submit a task to the local scheduler."},
|
||||
{"get_task", (PyCFunction) PyLocalSchedulerClient_get_task, METH_NOARGS,
|
||||
"Get a task from the local scheduler."},
|
||||
{"reconstruct_object",
|
||||
(PyCFunction) PyLocalSchedulerClient_reconstruct_object, METH_VARARGS,
|
||||
"Ask the local scheduler to reconstruct an object."},
|
||||
{"log_event", (PyCFunction) PyLocalSchedulerClient_log_event, METH_VARARGS,
|
||||
"Log an event to the event log through the local scheduler."},
|
||||
{"notify_unblocked", (PyCFunction) PyLocalSchedulerClient_notify_unblocked,
|
||||
METH_NOARGS, "Notify the local scheduler that we are unblocked."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject PyLocalSchedulerClientType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0) /* ob_size */
|
||||
"local_scheduler.LocalSchedulerClient", /* tp_name */
|
||||
sizeof(PyLocalSchedulerClient), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor) PyLocalSchedulerClient_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
"LocalSchedulerClient object", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
PyLocalSchedulerClient_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc) PyLocalSchedulerClient_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
||||
static PyMethodDef local_scheduler_methods[] = {
|
||||
{"check_simple_value", check_simple_value, METH_VARARGS,
|
||||
"Should the object be passed by value?"},
|
||||
{"compute_put_id", compute_put_id, METH_VARARGS,
|
||||
"Return the object ID for a put call within a task."},
|
||||
{"task_from_string", PyTask_from_string, METH_VARARGS,
|
||||
"Creates a Python PyTask object from a string representation of "
|
||||
"task_spec."},
|
||||
{"task_to_string", PyTask_to_string, METH_VARARGS,
|
||||
"Translates a PyTask python object to a byte string."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"liblocal_scheduler", /* m_name */
|
||||
"A module for the local scheduler.", /* m_doc */
|
||||
0, /* m_size */
|
||||
local_scheduler_methods, /* m_methods */
|
||||
NULL, /* m_reload */
|
||||
NULL, /* m_traverse */
|
||||
NULL, /* m_clear */
|
||||
NULL, /* m_free */
|
||||
};
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define INITERROR return NULL
|
||||
#else
|
||||
#define INITERROR return
|
||||
#endif
|
||||
|
||||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
|
||||
#define PyMODINIT_FUNC void
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#else
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
|
||||
#endif
|
||||
|
||||
MOD_INIT(liblocal_scheduler_library) {
|
||||
if (PyType_Ready(&PyTaskType) < 0) {
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&PyObjectIDType) < 0) {
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&PyLocalSchedulerClientType) < 0) {
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *m = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *m =
|
||||
Py_InitModule3("liblocal_scheduler_library", local_scheduler_methods,
|
||||
"A module for the local scheduler.");
|
||||
#endif
|
||||
|
||||
init_pickle_module();
|
||||
|
||||
Py_INCREF(&PyTaskType);
|
||||
PyModule_AddObject(m, "Task", (PyObject *) &PyTaskType);
|
||||
|
||||
Py_INCREF(&PyObjectIDType);
|
||||
PyModule_AddObject(m, "ObjectID", (PyObject *) &PyObjectIDType);
|
||||
|
||||
Py_INCREF(&PyLocalSchedulerClientType);
|
||||
PyModule_AddObject(m, "LocalSchedulerClient",
|
||||
(PyObject *) &PyLocalSchedulerClientType);
|
||||
|
||||
char local_scheduler_error[] = "local_scheduler.error";
|
||||
LocalSchedulerError = PyErr_NewException(local_scheduler_error, NULL, NULL);
|
||||
Py_INCREF(LocalSchedulerError);
|
||||
PyModule_AddObject(m, "local_scheduler_error", LocalSchedulerError);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PHOTON_H
|
||||
#define PHOTON_H
|
||||
#ifndef LOCAL_SCHEDULER_SHARED_H
|
||||
#define LOCAL_SCHEDULER_SHARED_H
|
||||
|
||||
#include "common/task.h"
|
||||
#include "common/state/table.h"
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "utarray.h"
|
||||
#include "uthash.h"
|
||||
|
||||
enum photon_message_type {
|
||||
enum local_scheduler_message_type {
|
||||
/** Notify the local scheduler that a task has finished. */
|
||||
TASK_DONE = 64,
|
||||
/** Get a new task from the local scheduler. */
|
||||
@@ -34,7 +34,7 @@ UT_icd workers_icd;
|
||||
UT_icd pid_t_icd;
|
||||
|
||||
/** This struct is used to register a new worker with the local scheduler.
|
||||
* It is shipped as part of photon_connect */
|
||||
* It is shipped as part of local_scheduler_connect */
|
||||
typedef struct {
|
||||
/** The ID of the actor. This is NIL_ACTOR_ID if the worker is not an actor.
|
||||
*/
|
||||
@@ -123,4 +123,4 @@ typedef struct {
|
||||
LocalSchedulerState *local_scheduler_state;
|
||||
} LocalSchedulerClient;
|
||||
|
||||
#endif /* PHOTON_H */
|
||||
#endif /* LOCAL_SCHEDULER_SHARED_H */
|
||||
+168
-135
@@ -16,16 +16,17 @@
|
||||
#include "state/object_table.h"
|
||||
#include "state/task_table.h"
|
||||
|
||||
#include "photon.h"
|
||||
#include "photon_scheduler.h"
|
||||
#include "photon_algorithm.h"
|
||||
#include "photon_client.h"
|
||||
#include "local_scheduler_shared.h"
|
||||
#include "local_scheduler.h"
|
||||
#include "local_scheduler_algorithm.h"
|
||||
#include "local_scheduler_client.h"
|
||||
|
||||
SUITE(photon_tests);
|
||||
SUITE(local_scheduler_tests);
|
||||
|
||||
const char *plasma_store_socket_name = "/tmp/plasma_store_socket_1";
|
||||
const char *plasma_manager_socket_name_format = "/tmp/plasma_manager_socket_%d";
|
||||
const char *photon_socket_name_format = "/tmp/photon_socket_%d";
|
||||
const char *local_scheduler_socket_name_format =
|
||||
"/tmp/local_scheduler_socket_%d";
|
||||
|
||||
int64_t timeout_handler(event_loop *loop, int64_t id, void *context) {
|
||||
event_loop_stop(loop);
|
||||
@@ -38,35 +39,36 @@ typedef struct {
|
||||
int plasma_manager_fd;
|
||||
/** A socket to communicate with the Plasma store. */
|
||||
int plasma_store_fd;
|
||||
/** Photon's socket for IPC requests. */
|
||||
int photon_fd;
|
||||
/** Photon's local scheduler state. */
|
||||
LocalSchedulerState *photon_state;
|
||||
/** Photon's event loop. */
|
||||
/** Local scheduler's socket for IPC requests. */
|
||||
int local_scheduler_fd;
|
||||
/** Local scheduler's local scheduler state. */
|
||||
LocalSchedulerState *local_scheduler_state;
|
||||
/** Local scheduler's event loop. */
|
||||
event_loop *loop;
|
||||
/** Number of Photon client connections, or mock workers. */
|
||||
int num_photon_conns;
|
||||
/** Photon client connections. */
|
||||
PhotonConnection **conns;
|
||||
} PhotonMock;
|
||||
/** Number of local scheduler client connections, or mock workers. */
|
||||
int num_local_scheduler_conns;
|
||||
/** Local scheduler client connections. */
|
||||
LocalSchedulerConnection **conns;
|
||||
} LocalSchedulerMock;
|
||||
|
||||
PhotonMock *PhotonMock_init(int num_workers, int num_mock_workers) {
|
||||
LocalSchedulerMock *LocalSchedulerMock_init(int num_workers,
|
||||
int num_mock_workers) {
|
||||
const char *node_ip_address = "127.0.0.1";
|
||||
const char *redis_addr = node_ip_address;
|
||||
int redis_port = 6379;
|
||||
const double static_resource_conf[MAX_RESOURCE_INDEX] = {DEFAULT_NUM_CPUS,
|
||||
DEFAULT_NUM_GPUS};
|
||||
PhotonMock *mock = malloc(sizeof(PhotonMock));
|
||||
memset(mock, 0, sizeof(PhotonMock));
|
||||
LocalSchedulerMock *mock = malloc(sizeof(LocalSchedulerMock));
|
||||
memset(mock, 0, sizeof(LocalSchedulerMock));
|
||||
mock->loop = event_loop_create();
|
||||
/* Bind to the Photon port and initialize the Photon scheduler. */
|
||||
/* Bind to the local scheduler port and initialize the local scheduler. */
|
||||
UT_string *plasma_manager_socket_name = bind_ipc_sock_retry(
|
||||
plasma_manager_socket_name_format, &mock->plasma_manager_fd);
|
||||
mock->plasma_store_fd =
|
||||
connect_ipc_sock_retry(plasma_store_socket_name, 5, 100);
|
||||
UT_string *photon_socket_name =
|
||||
bind_ipc_sock_retry(photon_socket_name_format, &mock->photon_fd);
|
||||
CHECK(mock->plasma_store_fd >= 0 && mock->photon_fd >= 0);
|
||||
UT_string *local_scheduler_socket_name = bind_ipc_sock_retry(
|
||||
local_scheduler_socket_name_format, &mock->local_scheduler_fd);
|
||||
CHECK(mock->plasma_store_fd >= 0 && mock->local_scheduler_fd >= 0);
|
||||
|
||||
UT_string *worker_command;
|
||||
utstring_new(worker_command);
|
||||
@@ -77,11 +79,12 @@ PhotonMock *PhotonMock_init(int num_workers, int num_mock_workers) {
|
||||
"--redis-address=%s:%d",
|
||||
node_ip_address, plasma_store_socket_name,
|
||||
utstring_body(plasma_manager_socket_name),
|
||||
utstring_body(photon_socket_name), redis_addr, redis_port);
|
||||
utstring_body(local_scheduler_socket_name), redis_addr,
|
||||
redis_port);
|
||||
|
||||
mock->photon_state = LocalSchedulerState_init(
|
||||
mock->local_scheduler_state = LocalSchedulerState_init(
|
||||
"127.0.0.1", mock->loop, redis_addr, redis_port,
|
||||
utstring_body(photon_socket_name), plasma_store_socket_name,
|
||||
utstring_body(local_scheduler_socket_name), plasma_store_socket_name,
|
||||
utstring_body(plasma_manager_socket_name), NULL, false,
|
||||
static_resource_conf, utstring_body(worker_command), num_workers);
|
||||
|
||||
@@ -90,50 +93,50 @@ PhotonMock *PhotonMock_init(int num_workers, int num_mock_workers) {
|
||||
accept_client(mock->plasma_manager_fd);
|
||||
}
|
||||
|
||||
/* Connect a Photon client. */
|
||||
mock->num_photon_conns = num_mock_workers;
|
||||
mock->conns = malloc(sizeof(PhotonConnection *) * num_mock_workers);
|
||||
/* Connect a local scheduler client. */
|
||||
mock->num_local_scheduler_conns = num_mock_workers;
|
||||
mock->conns = malloc(sizeof(LocalSchedulerConnection *) * num_mock_workers);
|
||||
for (int i = 0; i < num_mock_workers; ++i) {
|
||||
mock->conns[i] =
|
||||
PhotonConnection_init(utstring_body(photon_socket_name), NIL_ACTOR_ID);
|
||||
new_client_connection(mock->loop, mock->photon_fd,
|
||||
(void *) mock->photon_state, 0);
|
||||
mock->conns[i] = LocalSchedulerConnection_init(
|
||||
utstring_body(local_scheduler_socket_name), NIL_ACTOR_ID);
|
||||
new_client_connection(mock->loop, mock->local_scheduler_fd,
|
||||
(void *) mock->local_scheduler_state, 0);
|
||||
}
|
||||
|
||||
utstring_free(worker_command);
|
||||
utstring_free(plasma_manager_socket_name);
|
||||
utstring_free(photon_socket_name);
|
||||
utstring_free(local_scheduler_socket_name);
|
||||
return mock;
|
||||
}
|
||||
|
||||
void PhotonMock_free(PhotonMock *mock) {
|
||||
void LocalSchedulerMock_free(LocalSchedulerMock *mock) {
|
||||
/* Disconnect clients. */
|
||||
for (int i = 0; i < mock->num_photon_conns; ++i) {
|
||||
PhotonConnection_free(mock->conns[i]);
|
||||
for (int i = 0; i < mock->num_local_scheduler_conns; ++i) {
|
||||
LocalSchedulerConnection_free(mock->conns[i]);
|
||||
}
|
||||
free(mock->conns);
|
||||
|
||||
/* Kill all the workers and run the event loop again so that the task table
|
||||
* updates propagate and the tasks in progress are freed. */
|
||||
LocalSchedulerClient **worker =
|
||||
(LocalSchedulerClient **) utarray_eltptr(mock->photon_state->workers, 0);
|
||||
LocalSchedulerClient **worker = (LocalSchedulerClient **) utarray_eltptr(
|
||||
mock->local_scheduler_state->workers, 0);
|
||||
while (worker != NULL) {
|
||||
kill_worker(*worker, true);
|
||||
worker = (LocalSchedulerClient **) utarray_eltptr(
|
||||
mock->photon_state->workers, 0);
|
||||
mock->local_scheduler_state->workers, 0);
|
||||
}
|
||||
event_loop_add_timer(mock->loop, 500,
|
||||
(event_loop_timer_handler) timeout_handler, NULL);
|
||||
event_loop_run(mock->loop);
|
||||
|
||||
/* This also frees mock->loop. */
|
||||
LocalSchedulerState_free(mock->photon_state);
|
||||
LocalSchedulerState_free(mock->local_scheduler_state);
|
||||
close(mock->plasma_store_fd);
|
||||
close(mock->plasma_manager_fd);
|
||||
free(mock);
|
||||
}
|
||||
|
||||
void reset_worker(PhotonMock *mock, LocalSchedulerClient *worker) {
|
||||
void reset_worker(LocalSchedulerMock *mock, LocalSchedulerClient *worker) {
|
||||
if (worker->task_in_progress) {
|
||||
Task_free(worker->task_in_progress);
|
||||
worker->task_in_progress = NULL;
|
||||
@@ -146,8 +149,8 @@ void reset_worker(PhotonMock *mock, LocalSchedulerClient *worker) {
|
||||
* value, the task should get assigned to a worker again.
|
||||
*/
|
||||
TEST object_reconstruction_test(void) {
|
||||
PhotonMock *photon = PhotonMock_init(0, 1);
|
||||
PhotonConnection *worker = photon->conns[0];
|
||||
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
|
||||
LocalSchedulerConnection *worker = local_scheduler->conns[0];
|
||||
|
||||
/* Create a task with zero dependencies and one return value. */
|
||||
task_spec *spec = example_task_spec(0, 1);
|
||||
@@ -170,41 +173,47 @@ TEST object_reconstruction_test(void) {
|
||||
if (pid == 0) {
|
||||
/* Make sure we receive the task twice. First from the initial submission,
|
||||
* and second from the reconstruct request. */
|
||||
photon_submit(worker, spec);
|
||||
task_spec *task_assigned = photon_get_task(worker);
|
||||
local_scheduler_submit(worker, spec);
|
||||
task_spec *task_assigned = local_scheduler_get_task(worker);
|
||||
ASSERT_EQ(memcmp(task_assigned, spec, task_spec_size(spec)), 0);
|
||||
task_spec *reconstruct_task = photon_get_task(worker);
|
||||
task_spec *reconstruct_task = local_scheduler_get_task(worker);
|
||||
ASSERT_EQ(memcmp(reconstruct_task, spec, task_spec_size(spec)), 0);
|
||||
/* Clean up. */
|
||||
free_task_spec(reconstruct_task);
|
||||
free_task_spec(task_assigned);
|
||||
free_task_spec(spec);
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
exit(0);
|
||||
} else {
|
||||
/* Run the event loop. NOTE: OSX appears to require the parent process to
|
||||
* listen for events on the open file descriptors. */
|
||||
event_loop_add_timer(photon->loop, 500,
|
||||
event_loop_add_timer(local_scheduler->loop, 500,
|
||||
(event_loop_timer_handler) timeout_handler, NULL);
|
||||
event_loop_run(photon->loop);
|
||||
event_loop_run(local_scheduler->loop);
|
||||
/* Set the task's status to TASK_STATUS_DONE to prevent the race condition
|
||||
* that would suppress object reconstruction. */
|
||||
Task *task = Task_alloc(spec, TASK_STATUS_DONE,
|
||||
get_db_client_id(photon->photon_state->db));
|
||||
task_table_add_task(photon->photon_state->db, task, NULL, NULL, NULL);
|
||||
Task *task = Task_alloc(
|
||||
spec, TASK_STATUS_DONE,
|
||||
get_db_client_id(local_scheduler->local_scheduler_state->db));
|
||||
task_table_add_task(local_scheduler->local_scheduler_state->db, task, NULL,
|
||||
NULL, NULL);
|
||||
/* Trigger reconstruction, and run the event loop again. */
|
||||
ObjectID return_id = task_return(spec, 0);
|
||||
photon_reconstruct_object(worker, return_id);
|
||||
event_loop_add_timer(photon->loop, 500,
|
||||
local_scheduler_reconstruct_object(worker, return_id);
|
||||
event_loop_add_timer(local_scheduler->loop, 500,
|
||||
(event_loop_timer_handler) timeout_handler, NULL);
|
||||
event_loop_run(photon->loop);
|
||||
event_loop_run(local_scheduler->loop);
|
||||
/* Wait for the child process to exit and check that there are no tasks
|
||||
* left in the local scheduler's task queue. Then, clean up. */
|
||||
wait(NULL);
|
||||
free_task_spec(spec);
|
||||
ASSERT_EQ(num_waiting_tasks(photon->photon_state->algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(photon->photon_state->algorithm_state), 0);
|
||||
PhotonMock_free(photon);
|
||||
ASSERT_EQ(num_waiting_tasks(
|
||||
local_scheduler->local_scheduler_state->algorithm_state),
|
||||
0);
|
||||
ASSERT_EQ(num_dispatch_tasks(
|
||||
local_scheduler->local_scheduler_state->algorithm_state),
|
||||
0);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
PASS();
|
||||
}
|
||||
}
|
||||
@@ -215,8 +224,8 @@ TEST object_reconstruction_test(void) {
|
||||
* should trigger reconstruction of all previous tasks in the lineage.
|
||||
*/
|
||||
TEST object_reconstruction_recursive_test(void) {
|
||||
PhotonMock *photon = PhotonMock_init(0, 1);
|
||||
PhotonConnection *worker = photon->conns[0];
|
||||
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
|
||||
LocalSchedulerConnection *worker = local_scheduler->conns[0];
|
||||
/* Create a chain of tasks, each one dependent on the one before it. Mark
|
||||
* each object as available so that tasks will run immediately. */
|
||||
const int NUM_TASKS = 10;
|
||||
@@ -224,8 +233,9 @@ TEST object_reconstruction_recursive_test(void) {
|
||||
specs[0] = example_task_spec(0, 1);
|
||||
for (int i = 1; i < NUM_TASKS; ++i) {
|
||||
ObjectID arg_id = task_return(specs[i - 1], 0);
|
||||
handle_object_available(photon->photon_state,
|
||||
photon->photon_state->algorithm_state, arg_id);
|
||||
handle_object_available(
|
||||
local_scheduler->local_scheduler_state,
|
||||
local_scheduler->local_scheduler_state->algorithm_state, arg_id);
|
||||
specs[i] = example_task_spec_with_args(1, 1, &arg_id);
|
||||
}
|
||||
|
||||
@@ -249,11 +259,11 @@ TEST object_reconstruction_recursive_test(void) {
|
||||
if (pid == 0) {
|
||||
/* Submit the tasks, and make sure each one gets assigned to a worker. */
|
||||
for (int i = 0; i < NUM_TASKS; ++i) {
|
||||
photon_submit(worker, specs[i]);
|
||||
local_scheduler_submit(worker, specs[i]);
|
||||
}
|
||||
/* Make sure we receive each task from the initial submission. */
|
||||
for (int i = 0; i < NUM_TASKS; ++i) {
|
||||
task_spec *task_assigned = photon_get_task(worker);
|
||||
task_spec *task_assigned = local_scheduler_get_task(worker);
|
||||
ASSERT_EQ(memcmp(task_assigned, specs[i], task_spec_size(task_assigned)),
|
||||
0);
|
||||
free_task_spec(task_assigned);
|
||||
@@ -261,7 +271,7 @@ TEST object_reconstruction_recursive_test(void) {
|
||||
/* Check that the workers receive all tasks in the final return object's
|
||||
* lineage during reconstruction. */
|
||||
for (int i = 0; i < NUM_TASKS; ++i) {
|
||||
task_spec *task_assigned = photon_get_task(worker);
|
||||
task_spec *task_assigned = local_scheduler_get_task(worker);
|
||||
bool found = false;
|
||||
for (int j = 0; j < NUM_TASKS; ++j) {
|
||||
if (specs[j] == NULL) {
|
||||
@@ -277,35 +287,41 @@ TEST object_reconstruction_recursive_test(void) {
|
||||
free_task_spec(task_assigned);
|
||||
ASSERT(found);
|
||||
}
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
exit(0);
|
||||
} else {
|
||||
/* Run the event loop. NOTE: OSX appears to require the parent process to
|
||||
* listen for events on the open file descriptors. */
|
||||
event_loop_add_timer(photon->loop, 500,
|
||||
event_loop_add_timer(local_scheduler->loop, 500,
|
||||
(event_loop_timer_handler) timeout_handler, NULL);
|
||||
event_loop_run(photon->loop);
|
||||
event_loop_run(local_scheduler->loop);
|
||||
/* Set the final task's status to TASK_STATUS_DONE to prevent the race
|
||||
* condition that would suppress object reconstruction. */
|
||||
Task *last_task = Task_alloc(specs[NUM_TASKS - 1], TASK_STATUS_DONE,
|
||||
get_db_client_id(photon->photon_state->db));
|
||||
task_table_add_task(photon->photon_state->db, last_task, NULL, NULL, NULL);
|
||||
Task *last_task = Task_alloc(
|
||||
specs[NUM_TASKS - 1], TASK_STATUS_DONE,
|
||||
get_db_client_id(local_scheduler->local_scheduler_state->db));
|
||||
task_table_add_task(local_scheduler->local_scheduler_state->db, last_task,
|
||||
NULL, NULL, NULL);
|
||||
/* Trigger reconstruction for the last object, and run the event loop
|
||||
* again. */
|
||||
ObjectID return_id = task_return(specs[NUM_TASKS - 1], 0);
|
||||
photon_reconstruct_object(worker, return_id);
|
||||
event_loop_add_timer(photon->loop, 500,
|
||||
local_scheduler_reconstruct_object(worker, return_id);
|
||||
event_loop_add_timer(local_scheduler->loop, 500,
|
||||
(event_loop_timer_handler) timeout_handler, NULL);
|
||||
event_loop_run(photon->loop);
|
||||
event_loop_run(local_scheduler->loop);
|
||||
/* Wait for the child process to exit and check that there are no tasks
|
||||
* left in the local scheduler's task queue. Then, clean up. */
|
||||
wait(NULL);
|
||||
ASSERT_EQ(num_waiting_tasks(photon->photon_state->algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(photon->photon_state->algorithm_state), 0);
|
||||
ASSERT_EQ(num_waiting_tasks(
|
||||
local_scheduler->local_scheduler_state->algorithm_state),
|
||||
0);
|
||||
ASSERT_EQ(num_dispatch_tasks(
|
||||
local_scheduler->local_scheduler_state->algorithm_state),
|
||||
0);
|
||||
for (int i = 0; i < NUM_TASKS; ++i) {
|
||||
free_task_spec(specs[i]);
|
||||
}
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
PASS();
|
||||
}
|
||||
}
|
||||
@@ -319,13 +335,13 @@ task_spec *object_reconstruction_suppression_spec;
|
||||
void object_reconstruction_suppression_callback(ObjectID object_id,
|
||||
void *user_context) {
|
||||
/* Submit the task after adding the object to the object table. */
|
||||
PhotonConnection *worker = user_context;
|
||||
photon_submit(worker, object_reconstruction_suppression_spec);
|
||||
LocalSchedulerConnection *worker = user_context;
|
||||
local_scheduler_submit(worker, object_reconstruction_suppression_spec);
|
||||
}
|
||||
|
||||
TEST object_reconstruction_suppression_test(void) {
|
||||
PhotonMock *photon = PhotonMock_init(0, 1);
|
||||
PhotonConnection *worker = photon->conns[0];
|
||||
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
|
||||
LocalSchedulerConnection *worker = local_scheduler->conns[0];
|
||||
|
||||
object_reconstruction_suppression_spec = example_task_spec(0, 1);
|
||||
ObjectID return_id = task_return(object_reconstruction_suppression_spec, 0);
|
||||
@@ -333,48 +349,52 @@ TEST object_reconstruction_suppression_test(void) {
|
||||
if (pid == 0) {
|
||||
/* Make sure we receive the task once. This will block until the
|
||||
* object_table_add callback completes. */
|
||||
task_spec *task_assigned = photon_get_task(worker);
|
||||
task_spec *task_assigned = local_scheduler_get_task(worker);
|
||||
ASSERT_EQ(memcmp(task_assigned, object_reconstruction_suppression_spec,
|
||||
task_spec_size(object_reconstruction_suppression_spec)),
|
||||
0);
|
||||
/* Trigger a reconstruction. We will check that no tasks get queued as a
|
||||
* result of this line in the event loop process. */
|
||||
photon_reconstruct_object(worker, return_id);
|
||||
local_scheduler_reconstruct_object(worker, return_id);
|
||||
/* Clean up. */
|
||||
free_task_spec(task_assigned);
|
||||
free_task_spec(object_reconstruction_suppression_spec);
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
exit(0);
|
||||
} else {
|
||||
/* Connect a plasma manager client so we can call object_table_add. */
|
||||
const char *db_connect_args[] = {"address", "127.0.0.1:12346"};
|
||||
DBHandle *db = db_connect("127.0.0.1", 6379, "plasma_manager", "127.0.0.1",
|
||||
2, db_connect_args);
|
||||
db_attach(db, photon->loop, false);
|
||||
db_attach(db, local_scheduler->loop, false);
|
||||
/* Add the object to the object table. */
|
||||
object_table_add(db, return_id, 1, (unsigned char *) NIL_DIGEST, NULL,
|
||||
object_reconstruction_suppression_callback,
|
||||
(void *) worker);
|
||||
/* Run the event loop. NOTE: OSX appears to require the parent process to
|
||||
* listen for events on the open file descriptors. */
|
||||
event_loop_add_timer(photon->loop, 1000,
|
||||
event_loop_add_timer(local_scheduler->loop, 1000,
|
||||
(event_loop_timer_handler) timeout_handler, NULL);
|
||||
event_loop_run(photon->loop);
|
||||
event_loop_run(local_scheduler->loop);
|
||||
/* Wait for the child process to exit and check that there are no tasks
|
||||
* left in the local scheduler's task queue. Then, clean up. */
|
||||
wait(NULL);
|
||||
ASSERT_EQ(num_waiting_tasks(photon->photon_state->algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(photon->photon_state->algorithm_state), 0);
|
||||
ASSERT_EQ(num_waiting_tasks(
|
||||
local_scheduler->local_scheduler_state->algorithm_state),
|
||||
0);
|
||||
ASSERT_EQ(num_dispatch_tasks(
|
||||
local_scheduler->local_scheduler_state->algorithm_state),
|
||||
0);
|
||||
free_task_spec(object_reconstruction_suppression_spec);
|
||||
db_disconnect(db);
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
PASS();
|
||||
}
|
||||
}
|
||||
|
||||
TEST task_dependency_test(void) {
|
||||
PhotonMock *photon = PhotonMock_init(0, 1);
|
||||
LocalSchedulerState *state = photon->photon_state;
|
||||
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
|
||||
LocalSchedulerState *state = local_scheduler->local_scheduler_state;
|
||||
SchedulingAlgorithmState *algorithm_state = state->algorithm_state;
|
||||
/* Get the first worker. */
|
||||
LocalSchedulerClient *worker =
|
||||
@@ -395,7 +415,7 @@ TEST task_dependency_test(void) {
|
||||
handle_worker_available(state, algorithm_state, worker);
|
||||
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
|
||||
reset_worker(photon, worker);
|
||||
reset_worker(local_scheduler, worker);
|
||||
|
||||
/* Check that the task gets queued in the waiting queue if the task is
|
||||
* submitted and a worker is available, but the input is not. */
|
||||
@@ -408,7 +428,7 @@ TEST task_dependency_test(void) {
|
||||
handle_object_available(state, algorithm_state, oid);
|
||||
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
|
||||
reset_worker(photon, worker);
|
||||
reset_worker(local_scheduler, worker);
|
||||
|
||||
/* Check that the task gets queued in the dispatch queue if the task is
|
||||
* submitted and the input is available, but no worker is available yet. */
|
||||
@@ -419,7 +439,7 @@ TEST task_dependency_test(void) {
|
||||
handle_worker_available(state, algorithm_state, worker);
|
||||
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
|
||||
reset_worker(photon, worker);
|
||||
reset_worker(local_scheduler, worker);
|
||||
|
||||
/* If an object gets removed, check the first scenario again, where the task
|
||||
* gets queued in the waiting task if the task is submitted and a worker is
|
||||
@@ -443,13 +463,13 @@ TEST task_dependency_test(void) {
|
||||
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
|
||||
|
||||
free_task_spec(spec);
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST task_multi_dependency_test(void) {
|
||||
PhotonMock *photon = PhotonMock_init(0, 1);
|
||||
LocalSchedulerState *state = photon->photon_state;
|
||||
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
|
||||
LocalSchedulerState *state = local_scheduler->local_scheduler_state;
|
||||
SchedulingAlgorithmState *algorithm_state = state->algorithm_state;
|
||||
/* Get the first worker. */
|
||||
LocalSchedulerClient *worker =
|
||||
@@ -476,7 +496,7 @@ TEST task_multi_dependency_test(void) {
|
||||
handle_worker_available(state, algorithm_state, worker);
|
||||
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
|
||||
reset_worker(photon, worker);
|
||||
reset_worker(local_scheduler, worker);
|
||||
|
||||
/* Check that the task gets queued in the dispatch queue if the task is
|
||||
* submitted and the inputs are available, but no worker is available yet. */
|
||||
@@ -514,77 +534,90 @@ TEST task_multi_dependency_test(void) {
|
||||
handle_worker_available(state, algorithm_state, worker);
|
||||
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
|
||||
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
|
||||
reset_worker(photon, worker);
|
||||
reset_worker(local_scheduler, worker);
|
||||
|
||||
free_task_spec(spec);
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST start_kill_workers_test(void) {
|
||||
/* Start some workers. */
|
||||
int num_workers = 4;
|
||||
PhotonMock *photon = PhotonMock_init(num_workers, 0);
|
||||
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(num_workers, 0);
|
||||
/* We start off with num_workers children processes, but no workers
|
||||
* registered yet. */
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), num_workers);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), 0);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids),
|
||||
num_workers);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers), 0);
|
||||
|
||||
/* Make sure that each worker connects to the photon scheduler. This for loop
|
||||
* will hang if one of the workers does not connect. */
|
||||
/* Make sure that each worker connects to the local_scheduler scheduler. This
|
||||
* for loop will hang if one of the workers does not connect. */
|
||||
for (int i = 0; i < num_workers; ++i) {
|
||||
new_client_connection(photon->loop, photon->photon_fd,
|
||||
(void *) photon->photon_state, 0);
|
||||
new_client_connection(local_scheduler->loop,
|
||||
local_scheduler->local_scheduler_fd,
|
||||
(void *) local_scheduler->local_scheduler_state, 0);
|
||||
}
|
||||
|
||||
/* After handling each worker's initial connection, we should now have all
|
||||
* workers accounted for, but we haven't yet matched up process IDs with our
|
||||
* children processes. */
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), num_workers);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids),
|
||||
num_workers);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
|
||||
num_workers);
|
||||
|
||||
/* Each worker should register its process ID. */
|
||||
for (int i = 0; i < utarray_len(photon->photon_state->workers); ++i) {
|
||||
for (int i = 0;
|
||||
i < utarray_len(local_scheduler->local_scheduler_state->workers); ++i) {
|
||||
LocalSchedulerClient *worker = *(LocalSchedulerClient **) utarray_eltptr(
|
||||
photon->photon_state->workers, i);
|
||||
process_message(photon->photon_state->loop, worker->sock, worker, 0);
|
||||
local_scheduler->local_scheduler_state->workers, i);
|
||||
process_message(local_scheduler->local_scheduler_state->loop, worker->sock,
|
||||
worker, 0);
|
||||
}
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 0);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 0);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
|
||||
num_workers);
|
||||
|
||||
/* After killing a worker, its state is cleaned up. */
|
||||
LocalSchedulerClient *worker = *(LocalSchedulerClient **) utarray_eltptr(
|
||||
photon->photon_state->workers, 0);
|
||||
local_scheduler->local_scheduler_state->workers, 0);
|
||||
kill_worker(worker, false);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 0);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers - 1);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 0);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
|
||||
num_workers - 1);
|
||||
|
||||
/* Start a worker after the local scheduler has been initialized. */
|
||||
start_worker(photon->photon_state, NIL_ACTOR_ID);
|
||||
start_worker(local_scheduler->local_scheduler_state, NIL_ACTOR_ID);
|
||||
/* Accept the workers as clients to the plasma manager. */
|
||||
int new_worker_fd = accept_client(photon->plasma_manager_fd);
|
||||
int new_worker_fd = accept_client(local_scheduler->plasma_manager_fd);
|
||||
/* The new worker should register its process ID. */
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 1);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers - 1);
|
||||
/* Make sure the new worker connects to the photon scheduler. */
|
||||
new_client_connection(photon->loop, photon->photon_fd,
|
||||
(void *) photon->photon_state, 0);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 1);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 1);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
|
||||
num_workers - 1);
|
||||
/* Make sure the new worker connects to the local_scheduler scheduler. */
|
||||
new_client_connection(local_scheduler->loop,
|
||||
local_scheduler->local_scheduler_fd,
|
||||
(void *) local_scheduler->local_scheduler_state, 0);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 1);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
|
||||
num_workers);
|
||||
/* Make sure that the new worker registers its process ID. */
|
||||
worker = *(LocalSchedulerClient **) utarray_eltptr(
|
||||
photon->photon_state->workers, num_workers - 1);
|
||||
process_message(photon->photon_state->loop, worker->sock, worker, 0);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 0);
|
||||
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
|
||||
local_scheduler->local_scheduler_state->workers, num_workers - 1);
|
||||
process_message(local_scheduler->local_scheduler_state->loop, worker->sock,
|
||||
worker, 0);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 0);
|
||||
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
|
||||
num_workers);
|
||||
|
||||
/* Clean up. */
|
||||
close(new_worker_fd);
|
||||
PhotonMock_free(photon);
|
||||
LocalSchedulerMock_free(local_scheduler);
|
||||
PASS();
|
||||
}
|
||||
|
||||
SUITE(photon_tests) {
|
||||
SUITE(local_scheduler_tests) {
|
||||
RUN_REDIS_TEST(object_reconstruction_test);
|
||||
RUN_REDIS_TEST(object_reconstruction_recursive_test);
|
||||
RUN_REDIS_TEST(object_reconstruction_suppression_test);
|
||||
@@ -597,6 +630,6 @@ GREATEST_MAIN_DEFS();
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
GREATEST_MAIN_BEGIN();
|
||||
RUN_SUITE(photon_tests);
|
||||
RUN_SUITE(local_scheduler_tests);
|
||||
GREATEST_MAIN_END();
|
||||
}
|
||||
@@ -9,6 +9,6 @@ set -e
|
||||
sleep 1s
|
||||
./src/plasma/plasma_store -s /tmp/plasma_store_socket_1 -m 100000000 &
|
||||
sleep 0.5s
|
||||
./src/photon/photon_tests
|
||||
./src/local_scheduler/local_scheduler_tests
|
||||
./src/common/thirdparty/redis/src/redis-cli shutdown
|
||||
killall plasma_store
|
||||
@@ -9,6 +9,6 @@ set -e
|
||||
sleep 1s
|
||||
./src/plasma/plasma_store -s /tmp/plasma_store_socket_1 -m 100000000 &
|
||||
sleep 0.5s
|
||||
valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./src/photon/photon_tests
|
||||
valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./src/local_scheduler/local_scheduler_tests
|
||||
./src/common/thirdparty/redis/src/redis-cli shutdown
|
||||
killall plasma_store
|
||||
@@ -1,45 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(photon)
|
||||
|
||||
# Recursively include common
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../common/cmake/Common.cmake)
|
||||
|
||||
if(APPLE)
|
||||
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
|
||||
endif(APPLE)
|
||||
|
||||
include_directories("${PYTHON_INCLUDE_DIRS}")
|
||||
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} --std=c99 -Werror")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
link_libraries(rt)
|
||||
endif()
|
||||
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/")
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../")
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../plasma/")
|
||||
|
||||
add_library(photon SHARED
|
||||
photon_extension.c
|
||||
../common/lib/python/common_extension.c)
|
||||
|
||||
get_filename_component(PYTHON_SHARED_LIBRARY ${PYTHON_LIBRARIES} NAME)
|
||||
if(APPLE)
|
||||
add_custom_command(TARGET photon
|
||||
POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change ${PYTHON_SHARED_LIBRARY} ${PYTHON_LIBRARIES} libphoton.so)
|
||||
endif(APPLE)
|
||||
|
||||
add_library(photon_client STATIC photon_client.c)
|
||||
|
||||
target_link_libraries(photon photon_client ${COMMON_LIB} ${PYTHON_LIBRARIES})
|
||||
|
||||
add_executable(photon_scheduler photon_scheduler.c photon_algorithm.c)
|
||||
target_link_libraries(photon_scheduler photon_client common ${HIREDIS_LIB} plasma_lib)
|
||||
|
||||
add_executable(photon_tests test/photon_tests.c photon_scheduler.c photon_algorithm.c )
|
||||
target_link_libraries(photon_tests photon_client common ${HIREDIS_LIB} plasma_lib)
|
||||
target_compile_options(photon_tests PUBLIC "-DPHOTON_TEST")
|
||||
|
||||
install(TARGETS photon DESTINATION ${CMAKE_SOURCE_DIR}/photon)
|
||||
@@ -1,225 +0,0 @@
|
||||
#include <Python.h>
|
||||
|
||||
#include "common_extension.h"
|
||||
#include "photon_client.h"
|
||||
#include "task.h"
|
||||
|
||||
PyObject *PhotonError;
|
||||
|
||||
// clang-format off
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PhotonConnection *photon_connection;
|
||||
} PyPhotonClient;
|
||||
// clang-format on
|
||||
|
||||
static int PyPhotonClient_init(PyPhotonClient *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds) {
|
||||
char *socket_name;
|
||||
ActorID actor_id;
|
||||
if (!PyArg_ParseTuple(args, "sO&", &socket_name, PyStringToUniqueID,
|
||||
&actor_id)) {
|
||||
return -1;
|
||||
}
|
||||
/* Connect to the Photon scheduler. */
|
||||
self->photon_connection = PhotonConnection_init(socket_name, actor_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PyPhotonClient_dealloc(PyPhotonClient *self) {
|
||||
PhotonConnection_free(((PyPhotonClient *) self)->photon_connection);
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
static PyObject *PyPhotonClient_submit(PyObject *self, PyObject *args) {
|
||||
PyObject *py_task;
|
||||
if (!PyArg_ParseTuple(args, "O", &py_task)) {
|
||||
return NULL;
|
||||
}
|
||||
photon_submit(((PyPhotonClient *) self)->photon_connection,
|
||||
((PyTask *) py_task)->spec);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static PyObject *PyPhotonClient_get_task(PyObject *self) {
|
||||
task_spec *task_spec;
|
||||
/* Drop the global interpreter lock while we get a task because
|
||||
* photon_get_task may block for a long time. */
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
task_spec = photon_get_task(((PyPhotonClient *) self)->photon_connection);
|
||||
Py_END_ALLOW_THREADS
|
||||
return PyTask_make(task_spec);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static PyObject *PyPhotonClient_reconstruct_object(PyObject *self,
|
||||
PyObject *args) {
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&", PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
photon_reconstruct_object(((PyPhotonClient *) self)->photon_connection,
|
||||
object_id);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *PyPhotonClient_log_event(PyObject *self, PyObject *args) {
|
||||
const char *key;
|
||||
int key_length;
|
||||
const char *value;
|
||||
int value_length;
|
||||
if (!PyArg_ParseTuple(args, "s#s#", &key, &key_length, &value,
|
||||
&value_length)) {
|
||||
return NULL;
|
||||
}
|
||||
photon_log_event(((PyPhotonClient *) self)->photon_connection,
|
||||
(uint8_t *) key, key_length, (uint8_t *) value,
|
||||
value_length);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *PyPhotonClient_notify_unblocked(PyObject *self) {
|
||||
photon_notify_unblocked(((PyPhotonClient *) self)->photon_connection);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef PyPhotonClient_methods[] = {
|
||||
{"submit", (PyCFunction) PyPhotonClient_submit, METH_VARARGS,
|
||||
"Submit a task to the local scheduler."},
|
||||
{"get_task", (PyCFunction) PyPhotonClient_get_task, METH_NOARGS,
|
||||
"Get a task from the local scheduler."},
|
||||
{"reconstruct_object", (PyCFunction) PyPhotonClient_reconstruct_object,
|
||||
METH_VARARGS, "Ask the local scheduler to reconstruct an object."},
|
||||
{"log_event", (PyCFunction) PyPhotonClient_log_event, METH_VARARGS,
|
||||
"Log an event to the event log through the local scheduler."},
|
||||
{"notify_unblocked", (PyCFunction) PyPhotonClient_notify_unblocked,
|
||||
METH_NOARGS, "Notify the local scheduler that we are unblocked."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject PyPhotonClientType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0) /* ob_size */
|
||||
"photon.PhotonClient", /* tp_name */
|
||||
sizeof(PyPhotonClient), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor) PyPhotonClient_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
"PhotonClient object", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
PyPhotonClient_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc) PyPhotonClient_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
||||
static PyMethodDef photon_methods[] = {
|
||||
{"check_simple_value", check_simple_value, METH_VARARGS,
|
||||
"Should the object be passed by value?"},
|
||||
{"compute_put_id", compute_put_id, METH_VARARGS,
|
||||
"Return the object ID for a put call within a task."},
|
||||
{"task_from_string", PyTask_from_string, METH_VARARGS,
|
||||
"Creates a Python PyTask object from a string representation of "
|
||||
"task_spec."},
|
||||
{"task_to_string", PyTask_to_string, METH_VARARGS,
|
||||
"Translates a PyTask python object to a byte string."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"libphoton", /* m_name */
|
||||
"A module for the local scheduler.", /* m_doc */
|
||||
0, /* m_size */
|
||||
photon_methods, /* m_methods */
|
||||
NULL, /* m_reload */
|
||||
NULL, /* m_traverse */
|
||||
NULL, /* m_clear */
|
||||
NULL, /* m_free */
|
||||
};
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define INITERROR return NULL
|
||||
#else
|
||||
#define INITERROR return
|
||||
#endif
|
||||
|
||||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
|
||||
#define PyMODINIT_FUNC void
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#else
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
|
||||
#endif
|
||||
|
||||
MOD_INIT(libphoton) {
|
||||
if (PyType_Ready(&PyTaskType) < 0) {
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&PyObjectIDType) < 0) {
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&PyPhotonClientType) < 0) {
|
||||
INITERROR;
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *m = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *m = Py_InitModule3("libphoton", photon_methods,
|
||||
"A module for the local scheduler.");
|
||||
#endif
|
||||
|
||||
init_pickle_module();
|
||||
|
||||
Py_INCREF(&PyTaskType);
|
||||
PyModule_AddObject(m, "Task", (PyObject *) &PyTaskType);
|
||||
|
||||
Py_INCREF(&PyObjectIDType);
|
||||
PyModule_AddObject(m, "ObjectID", (PyObject *) &PyObjectIDType);
|
||||
|
||||
Py_INCREF(&PyPhotonClientType);
|
||||
PyModule_AddObject(m, "PhotonClient", (PyObject *) &PyPhotonClientType);
|
||||
|
||||
char photon_error[] = "photon.error";
|
||||
PhotonError = PyErr_NewException(photon_error, NULL, NULL);
|
||||
Py_INCREF(PhotonError);
|
||||
PyModule_AddObject(m, "photon_error", PhotonError);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user