Xhprof kullanma file_scan_directory()
Ön sayfa yüklendiğinde yürütülmesi 10 saniyeden uzun sürdü. Neden bu kadar uzun sürmeli?
Bu xhprofile çıktısıdır:
Xhprof kullanma file_scan_directory()
Ön sayfa yüklendiğinde yürütülmesi 10 saniyeden uzun sürdü. Neden bu kadar uzun sürmeli?
Bu xhprofile çıktısıdır:
Yanıtlar:
Drupal 7'de bilinen bir sorundan etkilendiğiniz anlaşılıyor .
Büyük olasılıkla, birden fazla modül eksik olduğunda modül dizinini yeniden taramaktan kaçının . Kurulumunuzda bazı eksik modüller varsa olur. Sistem tablonuzu kontrol etmeye çalışın:
SELECT name, filename FROM system WHERE type = 'module' AND status = 1 ORDER BY filename
Ve hala etkin olan ancak dosya sisteminden eksik olan tüm modülleri temizleyin.
Genel olarak, Drupal 7, bu gibi talihsiz regresyonlar dışında, Drupal 6'dan çok daha kaynak dostu ve ölçeklendirilebilir.
Bu işlevlere baktığımızda, bir modül veya bir modülün tek bir dosyası eksik gibi görünüyor. Drupal_get_filename () ' a bir göz atın , istenen dosyayı bulamazsa bu işlevi çağıran drupal_system_listing () öğesini çağırır. Drupal_system_listing () öğesini çağırmadan hemen önce bir dpm (func_get_args ()) ekleyin, bu size hangi dosyayı bulamadığını söylemelidir.
Bu sorunun ortaya çıkmasının birkaç nedeni var ve büyük dehşet içinde, şimdi kendimi bu nedenler hakkında biraz bilgili buluyorum. Sinir bozucu bir şekilde, Drupal çekirdeğini 7.33+ sürümüne yükselttikten sonra bu sorunu fark ettiyseniz, bu modülü yükseltmemiş olsanız bile, bu herhangi bir modülde bir yazım hatası olabilir.
İlk olarak @Berdir'in bahsettiği bilinen hatayı kontrol etmek isteyebilirsiniz, özellikle de "kullanılmayan" modülleri kod tabanından kaldırıyorsanız. Etkinleştirilmiş ancak dosya sisteminden kaldırılmış modülleriniz olup olmadığını öğrenmek için, burada belirtilen gibi bir komut dosyası çalıştırabilir veya çalışacak bir sisteme çok siteli kurulum için yazılmış mayın kullanabilirsiniz. Drupal temel dizininden:
find sites -maxdepth 1 -iname '*.*' -type d | sed -rne 's:sites/(.+):echo \1; drush @\1 sqlq "select filename from system where status = 1" | grep "/" | sed -rne "s_(.+)_test -f \\1 || echo \\1_p" | bash:p' | bash
veya aşağıdakiler:
while read -r file; do [ -f "$file" ] || echo "$file is missing."; done < <(drush sqlq "SELECT filename FROM system WHERE status = 1")
Kod tabanından kaldırılmış bir modül bulursanız, @Berdir'in belirttiği sorunlardaki talimatları izleyin.
Durum böyle değilse, durumunuza büyük olasılıkla kaldırılmış ancak hala bir drupal_add_js çağrısı (# 1082892 sayıdaki 19 numaralı yorumdan itibaren) veya bir modül veya temadaki talihsiz bir yazım hatası gibi bir kodlama hatası neden olmaktadır. , örneğin imagecache_actions
(bkz. https://drupal.org/node/2381357 ).
Her durumda, bunun neden olduğunu tam olarak anlamak için, Drupal'ın hangi dosyayı bulamadığını tam olarak bilmeniz gerekir. Yani, Berdir yorumuna göre, geçici olarak kesmek olabilir drupal_get_filename
de bootstrap.inc
hemen çağrısı önce bir günlük veya mesaj çağrısı ekleyerek drupal_system_listing()
. Devel modülünüz kurulu dpm
ise çalışır; değilse, drupal_set_message
veya syslog kullanabilirsiniz . Örnekler:
dpm(func_get_args());
drupal_set_message(implode(', ', func_get_args()));
syslog(LOG_WARNING, implode(', ', func_get_args()));
Drupal'ın ne aradığını öğrendikten sonra, oradan nereye gideceğinizi anlayabileceğiniz iyi bir bahis. Benim sorunum olmayan modülden bir dosya eklemek için bir çağrı neden oldu imagcache_actions
(yazım hatası not edin). Bu nedenle, imagecache_actions
kod tabanımda (örneğin grep -r imagcache_actions .
) aradım ve 1.4 sürümü imagecache_canvasactions.module
modülünün herhangi bir işlev çağrısının dışında, dosya kapsamında, bir yazım hatasıyla kullandığını buldum. Yine, bu hata sadece Drupal 7.33+ sürümüne güncellendikten sonra ortaya çıktı. Zaten için bir sorun oluşturulduğunu imagecache_actions
, yamayı uyguladığını ve işe geri döndüğünü buldum .
Çok benzer bir sorunum vardı - file_scan_directory()
siteyi öldürüyordum. Her önbellek sifonu tarandığı node_modules
için özel temam içine gömülmüş bir huuge klasörü çıkıyor gulp
. Bu dosyaları tema klasöründen çıkarmak (ve gulpfile'mdaki bazı yolları güncellemek) benim için düzeltmiş gibi görünüyordu. Alternatif olarak: Bence hack yapabilirsiniz file.inc
:
'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519
file_scan_directory()
Tüm dosyalar, belirli bir dizin için eşleşen bir özyinelemeli fonksiyonudur. I / O sistem çağrıları açısından en pahalı olabilen kullanımları is_dir()
ve opendir()
PHP çağrıları. Basit Drupal önyükleme (örn. time drush ev ""
) file_scan_directory
Birkaç bin defadan fazla çağrı yapabilir (Drupal klasör hiyerarşinizin karmaşıklığına bağlı olarak, örneğin modül sayısı ve klasörleri).
Benim durumumda ben ~ 1500 çağrıları vardı file_scan_directory
toplam oluşan 2 çağrılarında 24 saniye ( drupal_system_listing
içinde common.inc
daha sonra diğer aramalar için özyinelemeli çağrılar tarafından bölünmüş olduğunu, file_scan_directory
it-öz.
G / Ç çağrılarındaki performansı artırmak için dosya önbelleğe almayı uygulamanız gerekir. Bu, OPCache ( opcache.enable=1
) kurup etkinleştirerek ve ayarlarını değiştirerek elde edilebilir (bkz: PHP OPCache nasıl kullanılır? ). Memcached / redis gibi bellek tabanlı önbellek kullanımı da önerilir.
Komut satırı arabirimini (örneğin drush
) kullanırken de etkinleştirmeniz gerekir opcache.enable_cli=1
.
Değişiklikten sonra, mevcut bazı hata ayıklayıcıları kullanarak daha fazla tüketilen sistem çağrılarını kontrol edebilirsiniz.
Örneğin
Linux'ta strace
( bitirmek için vur Ctrl- C):
sudo strace -c -fp $(pgrep -n php)
Unix kullanarak dtrace
( PHP'nin DTrace statik problarını kullanarak ), ör.
sudo dtrace -n 'inline string NAME = "php"; syscall:::entry /(NAME == strstr(NAME, execname)) || (execname == strstr(execname, NAME))/ { @num[probefunc] = count(); }'
Ayrıca optimize etmeyi drupal_system_listing()
veya file_scan_directory()
statik önbellek uygulayarak, ör.
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -2104,6 +2104,8 @@ function file_download_access($uri) {
* 'filename', and 'name' members corresponding to the matching files.
*/
function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
+ static $dirs = array();
+
// Merge in defaults.
$options += array(
'nomask' => '/(\.\.?|CVS)$/',
@@ -2120,7 +2122,12 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
if (!preg_match($options['nomask'], $filename) && $filename[0] != '.') {
$uri = "$dir/$filename";
$uri = file_stream_wrapper_uri_normalize($uri);
- if (is_dir($uri) && $options['recurse']) {
+
+ if (empty($dirs[$uri])) {
+ $dirs[$uri] = is_dir($uri);
+ }
+
+ if ($dirs[$uri] && $options['recurse']) {
// Give priority to files in this folder by merging them in after any subdirectory files.
$files = array_merge(file_scan_directory($uri, $mask, $options, $depth + 1), $files);
Veya, file_scan_directory
gelen aramaları önbelleğe almak için drupal_system_listing()
, şu adreste bulunan şu yamayı kontrol edin: file_scan_directory önbelleğe alınmalıdır .