Use
pod update --no-repo-updateWhat did you expected to happen?
Don't block at
Resolving dependencies of PodfileWhat happened instead?
I have a huge dependencies tree(about 15 depths),about 260 pcs(I use private pod repo in house).It use long time for resolving dependencies(taking up about 95% of the total time), about 35 minutes,i mind it's a problem.
Podfile
I use private pod repo in house,and i can't provide it.sorry.
I don't really know what to do without a reproduction case, sorry. You'll either have to share one or investigate yourself.
@segiddins OK,thank you very much.
@yanzhiwei147 The best course would be to run pod update through a profiler and figure out where the time is being spent and if that can be improved. E.g. like this person did https://github.com/CocoaPods/Molinillo/pull/39 with ruby-prof.
@yanzhiwei147 FYI, here's a intro to ruby-prof since I did the same in the linked CocoaPods/Molinillo#39.
I added gem 'ruby-prof' to my Gemfile and bundled...
Then ran a script like this:
def ruby_prof_block
require 'ruby-prof'
result = RubyProf.profile do
yield
end
File.open("./graphs/callstack.html", "w") do |file|
RubyProf::CallStackPrinter.new(result).print(file, :threshold => 0.5, :expansion => 1.0)
end
end
ruby_prof_block { require 'bundler/setup'} # whatever you want to profile in the block
See the output in the graphs directory.
Let me try it now.
Excuse me, i do not know how to run this ruby script,and it run before execute pod update? I hope to get your help. Thank you!
I assume you'll have to determine what pod update calls in ruby so you can do the same thing within the profiling block.
This is where the pod update CLI command lives: https://github.com/CocoaPods/CocoaPods/blob/242da6b56683dd173b1ab9f3c998308374c9415c/lib/cocoapods/command/update.rb
I _think_ you should be able to require that file into your profiling script and invoke it like so:
ruby_prof_block do
require 'cocoapods'
Pod::Command::Update.new(CLAide::ARGV.new([])).run
end
Thank you @alloy, that was the part I had no idea! 鉂わ笍
@jrafanie @alloy I try to run this script today, but it seem block all day.
Update all pods
Updating local specs repositories
CocoaPods 1.0.0.beta.8 is available.
To update use: `gem install cocoapods --pre`
[!] This is a test version we'd love you to try.
For more information see http://blog.cocoapods.org
and the CHANGELOG for this version http://git.io/BaH8pQ.
Analyzing dependencies
Pre-downloading: `RATreeView` from `https://github.com/Augustyniak/RATreeView.git`, commit `5c08a85`
Fetching podspec for `LanguageImport` from `project/Resources/i18n`
Fetching podspec for `SkinImport` from `project/Resources/skin`
@yanzhiwei147 If it takes 35 minutes with no profiling, it may never finish under rubyprof. Sorry, I didn't think of that.
Perhaps there is a way to run it with a smaller number of your dependencies so it doesn't take forever?
I would do this if possible:
pod update --no-repo-update with your current dependencies (with no profiling)Also, stackprof block might also yield some useful information since it has a lot less overhead since it's a sampling profiler. Add gem 'stackprof' to your Gemfile (requires ruby 2.1+ I believe)
def stack_prof_block
require 'stackprof'
StackProf.run(:mode => :wall, :out => "tmp/stackprof.dump") do
yield
end
end
stack_prof_block do
require 'cocoapods'
Pod::Command::Update.new(CLAide::ARGV.new([])).run
end
Then run stackprof tmp/stackprof.dump
Note, my output for bundler looks like this:
stackprof graphs/stackprof_21689.dump
==================================
Mode: wall(1000)
Samples: 1266 (3.28% miss rate)
GC: 168 (13.27%)
==================================
TOTAL (pct) SAMPLES (pct) FRAME
177 (14.0%) 94 (7.4%) Bundler::Molinillo::DependencyGraph#add_vertex
83 (6.6%) 83 (6.6%) Bundler::Molinillo::DependencyGraph::Vertex#initialize
1616 (127.6%) 72 (5.7%) Kernel#require
56 (4.4%) 56 (4.4%) Gem::BasicSpecification#internal_init
247 (19.5%) 39 (3.1%) block in Bundler::Molinillo::DependencyGraph#initialize_copy
38 (3.0%) 38 (3.0%) block in Bundler::Runtime#setup_manpath
37 (2.9%) 37 (2.9%) Bundler::Molinillo::DependencyGraph#add_edge_no_circular
34 (2.7%) 32 (2.5%) block in Gem::Specification#initialize
34 (2.7%) 31 (2.4%) Set#add
97 (7.7%) 25 (2.0%) Bundler::Index#search_by_dependency
...
Note, there's other options for wall/cpu time, object counts, etc.
Another option I've used in the past is to run simplecov to get a code coverage report (since it also has less overhead to run)... It's been useful for me because it can show you which lines were executed and how many times. Sometimes, just seeing some lines run so frequently can help figure out problems.
@jrafanie Sorry,i'm sick.The dump now available.you must change expand name to dump.
Below is after run stackprof tmp/stackprof.dump.
==================================
Mode: wall(1000)
Samples: 1058622 (0.31% miss rate)
GC: 132838 (12.55%)
==================================
TOTAL (pct) SAMPLES (pct) FRAME
193473 (18.3%) 193473 (18.3%) Pod::Specification#platform_hash
209329 (19.8%) 98023 (9.3%) Pod::Platform#initialize
90820 (8.6%) 57299 (5.4%) Pod::Requirement#initialize
54905 (5.2%) 54905 (5.2%) Pod::Version.correct?
104904 (9.9%) 49999 (4.7%) Pod::Version#initialize
146175 (13.8%) 30002 (2.8%) Pod::Dependency#initialize
59030 (5.6%) 27627 (2.6%) Pod::Specification::DSL::RootAttributesAccessors#name
27456 (2.6%) 27456 (2.6%) Pod::Podfile::TargetDefinition#get_hash_value
259925 (24.6%) 23473 (2.2%) Pod::Specification#deployment_target
33186 (3.1%) 20604 (1.9%) Pod::Requirement.parse
18480 (1.7%) 18480 (1.7%) Pod::Specification::DSL::RootAttributesAccessors#base_name
111307 (10.5%) 18248 (1.7%) Pod::Vendor::Gem::Version.create
28679 (2.7%) 18118 (1.7%) Pod::Vendor::Gem::Version#segments
20260 (1.9%) 15076 (1.4%) Pod::Specification::Consumer#prepare_value
63460 (6.0%) 14716 (1.4%) Pod::Version#<=>
14214 (1.3%) 14214 (1.3%) block in #<Module:0x007fc10b282098>.popen3
13208 (1.2%) 13208 (1.2%) Molinillo::DependencyGraph::Vertex#hash
103962 (9.8%) 13178 (1.2%) Pod::Requirement.create
196826 (18.6%) 12948 (1.2%) Pod::Podfile::TargetDefinition#platform
16929 (1.6%) 11286 (1.1%) Pod::Source#search
653955 (61.8%) 10788 (1.0%) Pod::Resolver#edge_is_valid_for_target?
10561 (1.0%) 10561 (1.0%) block in Pod::Vendor::Gem::Version#segments
11992 (1.1%) 10486 (1.0%) Pod::Dependency#==
9189 (0.9%) 9189 (0.9%) Pod::Specification#root?
11682347 (1103.5%) 7825 (0.7%) Pod::Resolver#valid_dependencies_for_target_from_node
7611 (0.7%) 7611 (0.7%) block in Pod::Version#numeric_segments
7383 (0.7%) 7383 (0.7%) Pod::Specification#default_subspecs
7316 (0.7%) 7316 (0.7%) Pod::Vendor::Gem::Version#version
249687 (23.6%) 7096 (0.7%) Molinillo::DependencyGraph::Vertex#recursive_predecessors
6508 (0.6%) 6508 (0.6%) Pod::Platform#to_sym
@yanzhiwei147 I am not familiar with cocoapods but the first two (Pod::Specification#platform_hash, Pod::Platform#initialize) seem related... Maybe you can decrease the large number of dependencies locally so you can get it to run normally in 2-5 minutes where stackprof shows simular % as above. Then, try rubyprof with this reduced dependency tree as described above to see what that shows.
Being naive to the code base, these samples from above are very interesting since they seem to show up in similar number of TOTAL samples... Maybe they're called N times, where N is the size/complexity of the dependency tree:
259925 (24.6%) 23473 (2.2%) Pod::Specification#deployment_target
196826 (18.6%) 12948 (1.2%) Pod::Podfile::TargetDefinition#platform
193473 (18.3%) 193473 (18.3%) Pod::Specification#platform_hash
209329 (19.8%) 98023 (9.3%) Pod::Platform#initialize
I would wonder if you have dependencies that are specifying a large number of platforms in their specification.
If platform_hash is expensive, it's interesting that both deployment_target and supported_platform_names call platform_hash without caching the result here and here. I don't know if deployment_target and supported_platform_names are called multiple times per specification but caching/memoizing platform_hash (if it doesn't change) might help.
Looks like we might want to cache creating of Dependency and Version objects like RubyGems does, and probably cache platform hashes by podspec in the resolver (that way they can be GC'ed after resolution is done)
@segiddins What's the time to release it? I found the time is exponential order.
To release what?
This might speed up our pod install/update as well. We have around 75 pods in our project.
I also wonder why installation of pods couldnt be parallelized?
@jafara we tried parallelization but decided it wasn't worth the complexity
Could some of the resolution results be baked into the Lockfile to speed it up ? I think having a more expensive hit on an update is acceptable since most of the time you only want to install.
@jcampbell05 they already are entirely baked into the lockfile when possible
@segiddins What's the time to release it? I found the time is exponential order.
@yanzhiwei147 this project is open source so you could try fixing it based on @segiddins's description 鈽濓笍 above. Time is limited for everyone, especially project maintainers who donate their limited time, so it's very helpful to provide as much information as you can.
It would be helpful if we had a simplified set of recreation steps to demonstrate the slowness but within a reasonable time. Aim for less than 5 minutes without profiling. Then, verify the stackprof results for the simplified case looks very similar to your 35 minute scenario. I'd imagine you could start with some of the dependencies in your project and start adding/removing dependencies until you get to 2-5 minutes unprofiled resolution time. Of course if maintainers have other suggestions, listen to them.
With that minimal recreation case, we might have a shot at proposing solutions based on @segiddins suggestions... or provide enough direction that maintainers could fix up and get merged.
If this is that painful for you, see if you can provide the steps to reproduce it as described above. We all want painful slowness fixed.
Thank you for your reply. I have 65 pods(At Podfile),but it have 1510 leafs in dependency tree(it can A->B, B->C. It's possible exist A->C).I do not know how to get back to you.
@yanzhiwei147 the fastest way to get this improved will be for you to make a PR -- I don't know when I'll have time to look into performance improvements next
I recently came across the same situation, I have around 200 pods dependencies in our project. The CI compile process is long and painful, even with "--no-repo-update" options. The android project also got same dependencies number, but looks like Gradle and Maven works fine.
@wupher how does your stackprof output look compared to above? Where is your Podfile? How can I recreate it? What is your version or ruby version? We can't fix something we can't measure.
I try to find out what's wrong with it. It seems something wrong on molinillo's recursive_predecessors:

@segiddins I'm sorry i can't fix it and make a PR. I have not learned Ruby,Otherwise i also hope that their contribution to a force. Your easy work for me is hard work.
http://stackoverflow.com/questions/23006683/cocoapods-staying-on-analyzing-dependencies
is like this problem?
http://stackoverflow.com/questions/23006683/cocoapods-staying-on-analyzing-dependencies
is like this problem?
@jkluolin3000 No, it's complicated than you think.
@wupher thanks. The problem is it appears to be a specific dependency traversal problem, possibly due to cycles in the dependencies or many pods with many dependencies, but your Podfile doesn't appear to have public pods, so I can't run it. Is there open source app with a Podfile that you can recreate this issue on? Otherwise, we're guessing where the problem is.
If you can't provide a Podfile with public pods, you'll have to investigate the problem.
Artsy/Eigen has a podfile with ~60 pods in it - but we don't see any of these problems alas
thank you guys, I'll try to recreate the issue with public pod dependencies.
@jrafanie I move the private specs repo to github,now you can reappear this issue by yourself:
Cocoapods version 0.39.0Podfile contentsource 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/SlowDepend/Specs.git'
pod 'MUIKit'
pod 'MUPFoundation'
pod 'BlocksKit'
#com.nd.sdp:uc_component:release
pod 'UCComponent', '0.2.107'
pod 'UCSDK','0.10.76'
pod 'VirtualOrgSDK','1.0.25'
pod 'UCExtend', '0.2.29'
pod 'ContentServiceSDK', '0.2.51'
pod 'CephS3SDK','1.3.0'
#com.nd.smartcan.appfactory:main_component:release
pod 'APFMainComponent', '0.2.67'
pod 'APFKit', '0.1.69'
pod 'MUPFoundationNetworking', '1.0.15'
pod 'SmartCan', '0.5.24'
pod 'APFWebKit', '1.0.25'
pod 'SMCDataLayer', '0.4.19'
pre_install do
system("sed -i '' '/UITextField/d' Pods/BlocksKit/BlocksKit/BlocksKit+UIKit.h")
system('rm Pods/BlocksKit/BlocksKit/UIKit/UITextField+BlocksKit.h')
system('rm Pods/BlocksKit/BlocksKit/UIKit/UITextField+BlocksKit.m')
end
#com.nd.social:backpack:release
pod 'BackpackComponent', '6.5.1'
#com.nd.social:im:release
pod 'IMSComponent', '6.5.6'
pod 'IMSDK','6.5.6'
pod 'RATreeView', :git => 'https://github.com/kukushi/RATreeView.git', :commit => 'a4c96cb38bcd95f405b26d59363add1bd397d846'
#com.nd.social:voting:release
pod 'VotingComponent', '0.2.34'
#com.nd.social:notice:release
pod 'NoticeComponent', '0.3.45'
#com.nd.social:appbox:release
pod 'AppBoxComponent','6.3.0'
#com.nd.social:weibo:release
pod 'MicroBlogComponent','6.6.1'
#com.nd.social:lottery:release
pod 'LotteryComponent', '6.1.1'
#com.nd.social:appsetting:release
pod 'AppSettingComponent','6.5.0'
#com.nd.social:flower:release
pod 'SendFlowerComponent', '6.6.0'
#com.nd.social:ERP:release
pod 'ERPComponent','0.6.27'
pod 'CLOfficeSDK', '0.1.39'
pod 'COCommonUIKit', '0.1.55'
#com.nd.social:birthdaywishes:release
pod 'BirthdayWishesComponent', '0.4.4'
#com.nd.social:me:release
pod 'MeComponent','6.3.0'
#com.nd.social:greenhandguide:release
pod 'GreenHandGuideComponent','0.1.7'
#com.nd.social:netdisk:release
pod 'YunPanComponent', '0.4.15'
#com.nd.sdp:common_skin_component:release
pod 'CommonSkinComponent', ' 1.2.9'
#com.nd.social:forum:release
pod 'ForumComponent', '6.5.0'
pod 'RATreeView', :git => 'https://github.com/kukushi/RATreeView.git', :commit => 'a4c96cb38bcd95f405b26d59363add1bd397d846'
#com.nd.social:news:release
pod 'NewsComponent', '6.5.1'
#com.nd.erp:employee:release
pod 'ProfileComponent', '0.2.10'
#com.nd.erp:esop:release
pod 'ESOPComponent', '0.0.21'
#com.nd.erp:violation:release
#com.nd.erp:integral:release
#com.nd.erp:atnd:release
pod 'ATNDComponent','0.2.9'
#com.nd.social:qr-code:release
pod 'QRCodeComponent', '0.2.11'
#com.nd.social:activity:release
pod 'ActivityComponent','6.3.4'
#com.nd.hy:elearning:release
pod 'elearning2', '3.5.11'
#com.nd.sdp:data_analysis_component:release
pod 'DAComponent', '1.0.12'
#com.nd.erp:goods:release
#com.nd.sdp.component:crashreport:release
#com.nd.social:lbs:release
pod 'LBSComponent', '0.0.27'
#com.nd.social:vote:release
pod 'VoteComponent', '6.6.0'
#com.nd.oa:improve-info:release
pod 'ImproveInfoComponent', '0.0.6'
#com.nd.social:cloudalbum:release
pod 'CloudPhotoAlbumComponent', '0.1.15'
#com.nd.social:donatecomponent:release
pod 'SocialDonateComponent', '6.2.6'
#com.nd.social:collection:release
pod 'CollectionComponent', '0.4.9'
#com.nd.cloudoffice:sign:release
pod 'CloudSignInComponent', '1.1.54'
#com.nd.cloud:cloud-db:release
#com.nd.social:emotionmall:release
pod 'MUIExpressionMallComponent', '0.0.12'
#com.nd.sdp.component.cloudatlas:cloud-atlas-component-bussiness:release
pod 'cloudatlas_ios_component', '0.7.1'
#com.nd.social:appextention:release
$ pod repo add slow_dependency https://github.com/SlowDepend/Specs.git
$ pod update --verbose
@jrafanie It calculate too many times? Maybe We can get a good idea to solve this problem. thank you very much.
Thanks @yanzhiwei147. I'll try to run some tests the next few days.
Do you have a Podfile.lock before you run pod update --verbose?
@jrafanie So what's the result to run this test case?
@yanzhiwei147 Thanks for providing a public set of pods to try this against. I'll try to get to it soon. My suggestions still stand above... Limit the podfile one dependency at a time until you get it to run in less than 5 minutes so you can profile it with ruby prof. Another option is to try running the same 5 minute run with simplecov (code coverage)... between stackprof, rubyprof and simplecov, we should be able to see if we have a really slow method, some method is run too often (same inputs, same outputs... it's not cached when it should be), etc.
I don't actually use cocoapods, only the shared resolver, Molinillo, with bundler so I can only test this in my free time.
@jrafanie Thank you for you reply.I found this function can be optimized. It can be cached for follow up calc, now we run this command less than 40s. So should we make a PR to you?
@yanzhiwei147 yes, a PR would be much appreciated 馃槃
Fixed in #5578
Most helpful comment
thank you guys, I'll try to recreate the issue with public pod dependencies.