Releasing Python's GIL in C++ code where possible

Without this, all requests to the server become effectively serialized.
This commit is contained in:
Strahinja Val Markovic 2013-10-11 19:27:04 -07:00
parent 3ae10395ea
commit f6432e1498
9 changed files with 94 additions and 18 deletions

View File

@ -25,6 +25,7 @@
#include "CompletionData.h" #include "CompletionData.h"
#include "Utils.h" #include "Utils.h"
#include "ClangUtils.h" #include "ClangUtils.h"
#include "ReleaseGil.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
@ -59,6 +60,7 @@ ClangCompleter::~ClangCompleter() {
bool ClangCompleter::UpdatingTranslationUnit( const std::string &filename ) { bool ClangCompleter::UpdatingTranslationUnit( const std::string &filename ) {
ReleaseGil unlock;
shared_ptr< TranslationUnit > unit = translation_unit_store_.Get( filename ); shared_ptr< TranslationUnit > unit = translation_unit_store_.Get( filename );
if ( !unit ) if ( !unit )
@ -75,6 +77,7 @@ std::vector< Diagnostic > ClangCompleter::UpdateTranslationUnit(
const std::string &filename, const std::string &filename,
const std::vector< UnsavedFile > &unsaved_files, const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags ) { const std::vector< std::string > &flags ) {
ReleaseGil unlock;
bool translation_unit_created; bool translation_unit_created;
shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate(
filename, filename,
@ -111,6 +114,7 @@ ClangCompleter::CandidatesForLocationInFile(
int column, int column,
const std::vector< UnsavedFile > &unsaved_files, const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags ) { const std::vector< std::string > &flags ) {
ReleaseGil unlock;
shared_ptr< TranslationUnit > unit = shared_ptr< TranslationUnit > unit =
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
@ -129,6 +133,7 @@ Location ClangCompleter::GetDeclarationLocation(
int column, int column,
const std::vector< UnsavedFile > &unsaved_files, const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags ) { const std::vector< std::string > &flags ) {
ReleaseGil unlock;
shared_ptr< TranslationUnit > unit = shared_ptr< TranslationUnit > unit =
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
@ -146,6 +151,7 @@ Location ClangCompleter::GetDefinitionLocation(
int column, int column,
const std::vector< UnsavedFile > &unsaved_files, const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags ) { const std::vector< std::string > &flags ) {
ReleaseGil unlock;
shared_ptr< TranslationUnit > unit = shared_ptr< TranslationUnit > unit =
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
@ -158,6 +164,7 @@ Location ClangCompleter::GetDefinitionLocation(
void ClangCompleter::DeleteCachesForFile( const std::string &filename ) { void ClangCompleter::DeleteCachesForFile( const std::string &filename ) {
ReleaseGil unlock;
translation_unit_store_.Remove( filename ); translation_unit_store_.Remove( filename );
} }

View File

@ -18,6 +18,7 @@
#include "CompilationDatabase.h" #include "CompilationDatabase.h"
#include "ClangUtils.h" #include "ClangUtils.h"
#include "standard.h" #include "standard.h"
#include "ReleaseGil.h"
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
@ -58,6 +59,7 @@ bool CompilationDatabase::DatabaseSuccessfullyLoaded() {
CompilationInfoForFile CompilationDatabase::GetCompilationInfoForFile( CompilationInfoForFile CompilationDatabase::GetCompilationInfoForFile(
const std::string &path_to_file ) { const std::string &path_to_file ) {
ReleaseGil unlock;
CompilationInfoForFile info; CompilationInfoForFile info;
if ( !is_loaded_ ) if ( !is_loaded_ )

View File

@ -22,6 +22,7 @@
#include "IdentifierUtils.h" #include "IdentifierUtils.h"
#include "Result.h" #include "Result.h"
#include "Utils.h" #include "Utils.h"
#include "ReleaseGil.h"
#include <algorithm> #include <algorithm>
@ -49,6 +50,7 @@ void IdentifierCompleter::AddIdentifiersToDatabase(
const std::vector< std::string > &new_candidates, const std::vector< std::string > &new_candidates,
const std::string &filetype, const std::string &filetype,
const std::string &filepath ) { const std::string &filepath ) {
ReleaseGil unlock;
identifier_database_.AddIdentifiers( new_candidates, identifier_database_.AddIdentifiers( new_candidates,
filetype, filetype,
filepath ); filepath );
@ -57,6 +59,7 @@ void IdentifierCompleter::AddIdentifiersToDatabase(
void IdentifierCompleter::AddIdentifiersToDatabaseFromTagFiles( void IdentifierCompleter::AddIdentifiersToDatabaseFromTagFiles(
const std::vector< std::string > &absolute_paths_to_tag_files ) { const std::vector< std::string > &absolute_paths_to_tag_files ) {
ReleaseGil unlock;
foreach( const std::string & path, absolute_paths_to_tag_files ) { foreach( const std::string & path, absolute_paths_to_tag_files ) {
identifier_database_.AddIdentifiers( identifier_database_.AddIdentifiers(
ExtractIdentifiersFromTagsFile( path ) ); ExtractIdentifiersFromTagsFile( path ) );
@ -69,6 +72,7 @@ void IdentifierCompleter::AddIdentifiersToDatabaseFromBuffer(
const std::string &filetype, const std::string &filetype,
const std::string &filepath, const std::string &filepath,
bool collect_from_comments_and_strings ) { bool collect_from_comments_and_strings ) {
ReleaseGil unlock;
identifier_database_.ClearCandidatesStoredForFile( filetype, filepath ); identifier_database_.ClearCandidatesStoredForFile( filetype, filepath );
std::string new_contents = std::string new_contents =
@ -92,6 +96,7 @@ std::vector< std::string > IdentifierCompleter::CandidatesForQuery(
std::vector< std::string > IdentifierCompleter::CandidatesForQueryAndType( std::vector< std::string > IdentifierCompleter::CandidatesForQueryAndType(
const std::string &query, const std::string &query,
const std::string &filetype ) const { const std::string &filetype ) const {
ReleaseGil unlock;
std::vector< Result > results; std::vector< Result > results;
identifier_database_.ResultsForQueryAndType( query, filetype, results ); identifier_database_.ResultsForQueryAndType( query, filetype, results );

View File

@ -20,6 +20,8 @@
#include "Result.h" #include "Result.h"
#include "Candidate.h" #include "Candidate.h"
#include "CandidateRepository.h" #include "CandidateRepository.h"
#include "ReleaseGil.h"
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/cxx11/any_of.hpp> #include <boost/algorithm/cxx11/any_of.hpp>
#include <vector> #include <vector>
@ -76,15 +78,16 @@ boost::python::list FilterAndSortCandidates(
return candidates; return candidates;
} }
int num_candidates = len( candidates );
std::vector< const Candidate * > repository_candidates = std::vector< const Candidate * > repository_candidates =
CandidatesFromObjectList( candidates, candidate_property ); CandidatesFromObjectList( candidates, candidate_property );
std::vector< ResultAnd< int > > object_and_results;
{
ReleaseGil unlock;
Bitset query_bitset = LetterBitsetFromString( query ); Bitset query_bitset = LetterBitsetFromString( query );
bool query_has_uppercase_letters = any_of( query, is_upper() ); bool query_has_uppercase_letters = any_of( query, is_upper() );
int num_candidates = len( candidates );
std::vector< ResultAnd< int > > object_and_results;
for ( int i = 0; i < num_candidates; ++i ) { for ( int i = 0; i < num_candidates; ++i ) {
const Candidate *candidate = repository_candidates[ i ]; const Candidate *candidate = repository_candidates[ i ];
@ -101,6 +104,7 @@ boost::python::list FilterAndSortCandidates(
} }
std::sort( object_and_results.begin(), object_and_results.end() ); std::sort( object_and_results.begin(), object_and_results.end() );
}
foreach ( const ResultAnd< int > &object_and_result, foreach ( const ResultAnd< int > &object_and_result,
object_and_results ) { object_and_results ) {

42
cpp/ycm/ReleaseGil.h Normal file
View File

@ -0,0 +1,42 @@
// Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
//
// This file is part of YouCompleteMe.
//
// YouCompleteMe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// YouCompleteMe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
#ifndef RELEASEGIL_H_RDIEBSQ1
#define RELEASEGIL_H_RDIEBSQ1
#include <boost/python.hpp>
namespace YouCompleteMe {
class ReleaseGil {
public:
ReleaseGil() {
thread_state_ = PyEval_SaveThread();
}
~ReleaseGil() {
PyEval_RestoreThread( thread_state_ );
}
private:
PyThreadState *thread_state_;
};
} // namespace YouCompleteMe
#endif /* end of include guard: RELEASEGIL_H_RDIEBSQ1 */

View File

@ -68,7 +68,7 @@ add_executable( ${PROJECT_NAME}
target_link_libraries( ${PROJECT_NAME} target_link_libraries( ${PROJECT_NAME}
ycm_core ycm_core
gmock_main ) gmock )
if ( NOT CMAKE_GENERATOR_IS_XCODE ) if ( NOT CMAKE_GENERATOR_IS_XCODE )

13
cpp/ycm/tests/main.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <boost/python.hpp>
int main( int argc, char **argv ) {
Py_Initialize();
// Necessary because of usage of the ReleaseGil class
PyEval_InitThreads();
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -45,7 +45,7 @@ int YcmCoreVersion()
{ {
// We increment this every time when we want to force users to recompile // We increment this every time when we want to force users to recompile
// ycm_core. // ycm_core.
return 5; return 6;
} }
@ -54,6 +54,9 @@ BOOST_PYTHON_MODULE(ycm_core)
using namespace boost::python; using namespace boost::python;
using namespace YouCompleteMe; using namespace YouCompleteMe;
// Necessary because of usage of the ReleaseGil class
PyEval_InitThreads();
def( "HasClangSupport", HasClangSupport ); def( "HasClangSupport", HasClangSupport );
def( "FilterAndSortCandidates", FilterAndSortCandidates ); def( "FilterAndSortCandidates", FilterAndSortCandidates );
def( "YcmCoreVersion", YcmCoreVersion ); def( "YcmCoreVersion", YcmCoreVersion );

View File

@ -152,7 +152,7 @@ def AdjustCandidateInsertionText( candidates ):
return new_candidates return new_candidates
COMPATIBLE_WITH_CORE_VERSION = 5 COMPATIBLE_WITH_CORE_VERSION = 6
def CompatibleWithYcmCore(): def CompatibleWithYcmCore():
try: try: