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

View File

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

View File

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

View File

@ -20,6 +20,8 @@
#include "Result.h"
#include "Candidate.h"
#include "CandidateRepository.h"
#include "ReleaseGil.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/cxx11/any_of.hpp>
#include <vector>
@ -76,31 +78,33 @@ boost::python::list FilterAndSortCandidates(
return candidates;
}
int num_candidates = len( candidates );
std::vector< const Candidate * > repository_candidates =
CandidatesFromObjectList( candidates, candidate_property );
Bitset query_bitset = LetterBitsetFromString( query );
bool query_has_uppercase_letters = any_of( query, is_upper() );
int num_candidates = len( candidates );
std::vector< ResultAnd< int > > object_and_results;
{
ReleaseGil unlock;
Bitset query_bitset = LetterBitsetFromString( query );
bool query_has_uppercase_letters = any_of( query, is_upper() );
for ( int i = 0; i < num_candidates; ++i ) {
const Candidate *candidate = repository_candidates[ i ];
for ( int i = 0; i < num_candidates; ++i ) {
const Candidate *candidate = repository_candidates[ i ];
if ( !candidate->MatchesQueryBitset( query_bitset ) )
continue;
if ( !candidate->MatchesQueryBitset( query_bitset ) )
continue;
Result result = candidate->QueryMatchResult( query,
query_has_uppercase_letters );
Result result = candidate->QueryMatchResult( query,
query_has_uppercase_letters );
if ( result.IsSubsequence() ) {
ResultAnd< int > object_and_result( i, result );
object_and_results.push_back( boost::move( object_and_result ) );
if ( result.IsSubsequence() ) {
ResultAnd< int > object_and_result( i, result );
object_and_results.push_back( boost::move( object_and_result ) );
}
}
}
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,
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}
ycm_core
gmock_main )
gmock )
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
// ycm_core.
return 5;
return 6;
}
@ -54,6 +54,9 @@ BOOST_PYTHON_MODULE(ycm_core)
using namespace boost::python;
using namespace YouCompleteMe;
// Necessary because of usage of the ReleaseGil class
PyEval_InitThreads();
def( "HasClangSupport", HasClangSupport );
def( "FilterAndSortCandidates", FilterAndSortCandidates );
def( "YcmCoreVersion", YcmCoreVersion );

View File

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